From 0f26b26f1d93f002ccd5fe6b6fd636172bfbb24b Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 20 May 2014 10:03:30 +1200 Subject: [PATCH] Gdk: add an experimental backend for mir This is disabled by default. Enable with --enable-mir-backend. This backend is a combined work of Robert Ancell and Ryan Lortie. --- Makefile.am | 6 +- configure.ac | 34 +- docs/reference/gtk/Makefile.am | 1 + docs/reference/gtk/building.sgml | 11 +- docs/reference/gtk/gtk-docs.sgml | 1 + docs/reference/gtk/mir.xml | 35 + docs/reference/gtk/running.sgml | 5 + gdk/Makefile.am | 6 +- gdk/gdkdisplaymanager.c | 7 + gdk/mir/Makefile.am | 39 + gdk/mir/gdkmir-debug.c | 293 +++++++ gdk/mir/gdkmir-private.h | 86 +++ gdk/mir/gdkmir.h | 39 + gdk/mir/gdkmircursor.c | 73 ++ gdk/mir/gdkmirdevicemanager.c | 120 +++ gdk/mir/gdkmirdisplay.c | 572 ++++++++++++++ gdk/mir/gdkmireventsource.c | 624 +++++++++++++++ gdk/mir/gdkmirkeyboard.c | 173 +++++ gdk/mir/gdkmirkeymap.c | 466 +++++++++++ gdk/mir/gdkmirpointer.c | 250 ++++++ gdk/mir/gdkmirscreen.c | 720 +++++++++++++++++ gdk/mir/gdkmirwindow.c | 52 ++ gdk/mir/gdkmirwindowimpl.c | 1239 ++++++++++++++++++++++++++++++ gtk/gtktooltip.c | 16 + 24 files changed, 4861 insertions(+), 7 deletions(-) create mode 100644 docs/reference/gtk/mir.xml create mode 100644 gdk/mir/Makefile.am create mode 100644 gdk/mir/gdkmir-debug.c create mode 100644 gdk/mir/gdkmir-private.h create mode 100644 gdk/mir/gdkmir.h create mode 100644 gdk/mir/gdkmircursor.c create mode 100644 gdk/mir/gdkmirdevicemanager.c create mode 100644 gdk/mir/gdkmirdisplay.c create mode 100644 gdk/mir/gdkmireventsource.c create mode 100644 gdk/mir/gdkmirkeyboard.c create mode 100644 gdk/mir/gdkmirkeymap.c create mode 100644 gdk/mir/gdkmirpointer.c create mode 100644 gdk/mir/gdkmirscreen.c create mode 100644 gdk/mir/gdkmirwindow.c create mode 100644 gdk/mir/gdkmirwindowimpl.c diff --git a/Makefile.am b/Makefile.am index 2cb7769111..37bc9ff90e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,11 +33,11 @@ MAINTAINERCLEANFILES = \ ## Copy .pc files to target-specific names -gtk+-x11-3.0.pc gtk+-win32-3.0.pc gtk+-quartz-3.0.pc gtk+-broadway-3.0.pc gtk+-wayland-3.0.pc: gtk+-3.0.pc +gtk+-x11-3.0.pc gtk+-win32-3.0.pc gtk+-quartz-3.0.pc gtk+-broadway-3.0.pc gtk+-wayland-3.0.pc gtk+-mir-3.0.pc: gtk+-3.0.pc rm -f $@ && \ cp gtk+-3.0.pc $@ -gdk-x11-3.0.pc gdk-win32-3.0.pc gdk-quartz-3.0.pc gdk-broadway-3.0.pc gdk-wayland-3.0.pc: gdk-3.0.pc +gdk-x11-3.0.pc gdk-win32-3.0.pc gdk-quartz-3.0.pc gdk-broadway-3.0.pc gdk-wayland-3.0.pc gdk-mir-3.0.pc: gdk-3.0.pc rm -f $@ && \ cp gdk-3.0.pc $@ @@ -59,12 +59,14 @@ DISTCLEANFILES = \ gtk+-quartz-3.0.pc \ gtk+-broadway-3.0.pc \ gtk+-wayland-3.0.pc \ + gtk+-mir-3.0.pc \ gdk-3.0.pc \ gdk-x11-3.0.pc \ gdk-win32-3.0.pc \ gdk-quartz-3.0.pc \ gdk-broadway-3.0.pc \ gdk-wayland-3.0.pc \ + gdk-mir-3.0.pc \ gail-3.0.pc \ config.lt diff --git a/configure.ac b/configure.ac index d614dde0d7..4870bfc887 100644 --- a/configure.ac +++ b/configure.ac @@ -330,6 +330,10 @@ AC_ARG_ENABLE(wayland-backend, [AS_HELP_STRING([--enable-wayland-backend], [enable the wayland gdk backend])], [backend_set=yes]) +AC_ARG_ENABLE(mir-backend, + [AS_HELP_STRING([--enable-mir-backend], + [enable the Mir gdk backend])], + [backend_set=yes]) if test -z "$backend_set"; then if test "$platform_win32" = yes; then @@ -337,6 +341,7 @@ if test -z "$backend_set"; then else enable_x11_backend=yes enable_wayland_backend=maybe + enable_mir_backend=no fi fi @@ -459,6 +464,30 @@ else AM_CONDITIONAL(USE_WAYLAND, false) fi +MIR_DEPENDENCIES="mirclient" +if test "$enable_mir_backend" = "maybe" ; then + PKG_CHECK_EXISTS($MIR_DEPENDENCIES, [have_mir_deps=yes], [have_mir_deps=no]) + AC_MSG_CHECKING([for MIR_DEPENDENCIES]) + if test "$have_mir_deps" = "no" ; then + enable_mir_backend=no + else + enable_mir_backend=yes + fi + AC_MSG_RESULT($enable_mir_backend) +fi + +if test "$enable_mir_backend" = "yes"; then + cairo_backends="$cairo_backends cairo" + GDK_BACKENDS="$GDK_BACKENDS mir" + GDK_WINDOWING="$GDK_WINDOWING +#define GDK_WINDOWING_MIR" + MIR_PACKAGES="$MIR_DEPENDENCIES" + + AM_CONDITIONAL(USE_MIR, true) +else + AM_CONDITIONAL(USE_MIR, false) +fi + # strip leading space GDK_BACKENDS=${GDK_BACKENDS#* } @@ -1328,7 +1357,7 @@ CFLAGS="$saved_cflags" LDFLAGS="$saved_ldflags" GDK_PACKAGES="$PANGO_PACKAGES gdk-pixbuf-2.0 >= gdk_pixbuf_required_version cairo >= cairo_required_version cairo-gobject >= cairo_required_version" -GDK_PRIVATE_PACKAGES="$GDK_GIO_PACKAGE $X_PACKAGES $WAYLAND_PACKAGES $cairo_backends epoxy >= epoxy_required_version" +GDK_PRIVATE_PACKAGES="$GDK_GIO_PACKAGE $X_PACKAGES $WAYLAND_PACKAGES $MIR_PACKAGES $cairo_backends epoxy >= epoxy_required_version" if test "x$enable_x11_backend" = xyes; then GDK_PRIVATE_PACKAGES="$GDK_PRIVATE_PACKAGES pangoft2" fi @@ -1365,7 +1394,7 @@ fi PKG_CHECK_MODULES(ATK, $ATK_PACKAGES) GTK_PACKAGES="atk >= atk_required_version cairo >= cairo_required_version cairo-gobject >= cairo_required_version gdk-pixbuf-2.0 >= gdk_pixbuf_required_version gio-2.0 >= glib_required_version" -GTK_PRIVATE_PACKAGES="$ATK_PACKAGES" +GTK_PRIVATE_PACKAGES="$ATK_PACKAGES $WAYLAND_PACKAGES $MIR_PACKAGES" if test "x$enable_x11_backend" = xyes; then GTK_PRIVATE_PACKAGES="$GTK_PRIVATE_PACKAGES pangoft2" fi @@ -1915,6 +1944,7 @@ gdk/win32/rc/Makefile gdk/win32/rc/gdk.rc gdk/quartz/Makefile gdk/wayland/Makefile +gdk/mir/Makefile gdk/gdkversionmacros.h gtk/Makefile gtk/makefile.msc diff --git a/docs/reference/gtk/Makefile.am b/docs/reference/gtk/Makefile.am index 38bedac91b..3d881b15d6 100644 --- a/docs/reference/gtk/Makefile.am +++ b/docs/reference/gtk/Makefile.am @@ -146,6 +146,7 @@ content_files = \ osx.sgml \ broadway.xml \ wayland.xml \ + mir.xml \ question_index.sgml \ resources.sgml \ text_widget.sgml \ diff --git a/docs/reference/gtk/building.sgml b/docs/reference/gtk/building.sgml index f48f1aea5a..9c4b3abea2 100644 --- a/docs/reference/gtk/building.sgml +++ b/docs/reference/gtk/building.sgml @@ -407,6 +407,11 @@ How to compile GTK+ itself --disable-wayland-backend + + --enable-mir-backend + --disable-mir-backend + + --enable-introspection=[no/auto/yes] @@ -608,8 +613,10 @@ How to compile GTK+ itself --disable-quartz-backend, --enable-broadway-backend, --disable-broadway-backend, - --enable-wayland-backend, and - --disable-wayland-backend + --enable-wayland-backend, + --disable-wayland-backend + --enable-mir-backend, and + --disable-mir-backend Enables specific backends for GDK. If none of these options diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml index 16ed27eb95..e2ac6172f1 100644 --- a/docs/reference/gtk/gtk-docs.sgml +++ b/docs/reference/gtk/gtk-docs.sgml @@ -416,6 +416,7 @@ + diff --git a/docs/reference/gtk/mir.xml b/docs/reference/gtk/mir.xml new file mode 100644 index 0000000000..3a0a52e082 --- /dev/null +++ b/docs/reference/gtk/mir.xml @@ -0,0 +1,35 @@ + + + + +Using GTK+ with Mir +3 +GTK Library + + + +Using GTK+ with Mir + +Mir-specific aspects of using GTK+ + + + + +Using GTK+ with Mir + + +The GDK Mir backend provides support for running GTK+ applications +under Mir based display servers. To run your application in this way, +select the Mir backend by setting GDK_BACKEND=mir. + + + +Currently, the Mir backend does not use any additional commandline +options or environment variables. + + + + + diff --git a/docs/reference/gtk/running.sgml b/docs/reference/gtk/running.sgml index 3e5f688e8e..1c406a346a 100644 --- a/docs/reference/gtk/running.sgml +++ b/docs/reference/gtk/running.sgml @@ -491,6 +491,11 @@ nevertheless. Selects the Wayland backend for connecting to Wayland display servers + + mir + Selects the Mir backend for connecting to Mir display servers + + Since 3.10, this environment variable can contain a comma-separated list of backend names, which are tried in order. The list may also contain diff --git a/gdk/Makefile.am b/gdk/Makefile.am index 3ff5ff02cb..618dec533a 100644 --- a/gdk/Makefile.am +++ b/gdk/Makefile.am @@ -13,7 +13,7 @@ INTROSPECTION_COMPILER_ARGS = \ SUBDIRS = $(GDK_BACKENDS) . -DIST_SUBDIRS = win32 x11 quartz broadway wayland +DIST_SUBDIRS = win32 x11 quartz broadway wayland mir CLEANFILES = @@ -205,6 +205,10 @@ if USE_WAYLAND libgdk_3_la_LIBADD += wayland/libgdk-wayland.la endif +if USE_MIR +libgdk_3_la_LIBADD += mir/libgdk-mir.la +endif + if HAVE_INTROSPECTION introspection_files = \ diff --git a/gdk/gdkdisplaymanager.c b/gdk/gdkdisplaymanager.c index c6813d02bc..c9afbca11a 100644 --- a/gdk/gdkdisplaymanager.c +++ b/gdk/gdkdisplaymanager.c @@ -60,6 +60,10 @@ #include "wayland/gdkprivate-wayland.h" #endif +#ifdef GDK_WINDOWING_MIR +#include "mir/gdkmir-private.h" +#endif + /** * SECTION:gdkdisplaymanager * @Short_description: Maintains a list of all open GdkDisplays @@ -272,6 +276,9 @@ static GdkBackend gdk_backends[] = { #ifdef GDK_WINDOWING_WAYLAND { "wayland", _gdk_wayland_display_open }, #endif +#ifdef GDK_WINDOWING_MIR + { "mir", _gdk_mir_display_open }, +#endif #ifdef GDK_WINDOWING_BROADWAY { "broadway", _gdk_broadway_display_open }, #endif diff --git a/gdk/mir/Makefile.am b/gdk/mir/Makefile.am new file mode 100644 index 0000000000..026ce7981a --- /dev/null +++ b/gdk/mir/Makefile.am @@ -0,0 +1,39 @@ +## Process this file with automake to produce Makefile.in +include $(top_srcdir)/Makefile.decl + +libgdkincludedir = $(includedir)/gtk-3.0/gdk +libgdkmirincludedir = $(includedir)/gtk-3.0/gdk/mir + +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gdk\" \ + -DGDK_COMPILATION \ + -I$(top_srcdir) \ + -I$(top_srcdir)/gdk \ + -I$(top_builddir)/gdk \ + $(GDK_HIDDEN_VISIBILITY_CFLAGS) \ + $(GTK_DEBUG_FLAGS) \ + $(GDK_DEP_CFLAGS) + +LDADDS = $(GDK_DEP_LIBS) + +noinst_LTLIBRARIES = \ + libgdk-mir.la + +libgdk_mir_la_SOURCES = \ + gdkmircursor.c \ + gdkmirdevicemanager.c \ + gdkmirdisplay.c \ + gdkmireventsource.c \ + gdkmirkeyboard.c \ + gdkmirkeymap.c \ + gdkmirpointer.c \ + gdkmirscreen.c \ + gdkmirwindow.c \ + gdkmirwindowimpl.c \ + gdkmir-debug.c \ + gdkmir.h + +libgdkinclude_HEADERS = \ + gdkmir.h + +-include $(top_srcdir)/git.mk diff --git a/gdk/mir/gdkmir-debug.c b/gdk/mir/gdkmir-debug.c new file mode 100644 index 0000000000..ef57eff973 --- /dev/null +++ b/gdk/mir/gdkmir-debug.c @@ -0,0 +1,293 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "gdkmir-private.h" + +void +_gdk_mir_print_modifiers (unsigned int modifiers) +{ + g_printerr (" Modifiers"); + if ((modifiers & mir_key_modifier_alt) != 0) + g_printerr (" alt"); + if ((modifiers & mir_key_modifier_alt_left) != 0) + g_printerr (" alt-left"); + if ((modifiers & mir_key_modifier_alt_right) != 0) + g_printerr (" alt-right"); + if ((modifiers & mir_key_modifier_shift) != 0) + g_printerr (" shift"); + if ((modifiers & mir_key_modifier_shift_left) != 0) + g_printerr (" shift-left"); + if ((modifiers & mir_key_modifier_shift_right) != 0) + g_printerr (" shift-right"); + if ((modifiers & mir_key_modifier_sym) != 0) + g_printerr (" sym"); + if ((modifiers & mir_key_modifier_function) != 0) + g_printerr (" function"); + if ((modifiers & mir_key_modifier_ctrl) != 0) + g_printerr (" ctrl"); + if ((modifiers & mir_key_modifier_ctrl_left) != 0) + g_printerr (" ctrl-left"); + if ((modifiers & mir_key_modifier_ctrl_right) != 0) + g_printerr (" ctrl-right"); + if ((modifiers & mir_key_modifier_meta) != 0) + g_printerr (" meta"); + if ((modifiers & mir_key_modifier_meta_left) != 0) + g_printerr (" meta-left"); + if ((modifiers & mir_key_modifier_meta_right) != 0) + g_printerr (" meta-right"); + if ((modifiers & mir_key_modifier_caps_lock) != 0) + g_printerr (" caps-lock"); + if ((modifiers & mir_key_modifier_num_lock) != 0) + g_printerr (" num-lock"); + if ((modifiers & mir_key_modifier_scroll_lock) != 0) + g_printerr (" scroll-lock"); + g_printerr ("\n"); +} + +void +_gdk_mir_print_key_event (const MirKeyEvent *event) +{ + g_printerr ("KEY\n"); + g_printerr (" Device %i\n", event->device_id); + g_printerr (" Source %i\n", event->source_id); + g_printerr (" Action "); + switch (event->action) + { + case mir_key_action_down: + g_printerr ("down"); + break; + case mir_key_action_up: + g_printerr ("up"); + break; + case mir_key_action_multiple: + g_printerr ("multiple"); + break; + default: + g_printerr ("%u", event->action); + break; + } + g_printerr ("\n"); + g_printerr (" Flags"); + if ((event->flags & mir_key_flag_woke_here) != 0) + g_printerr (" woke-here"); + if ((event->flags & mir_key_flag_soft_keyboard) != 0) + g_printerr (" soft-keyboard"); + if ((event->flags & mir_key_flag_keep_touch_mode) != 0) + g_printerr (" keep-touch-mode"); + if ((event->flags & mir_key_flag_from_system) != 0) + g_printerr (" from-system"); + if ((event->flags & mir_key_flag_editor_action) != 0) + g_printerr (" editor-action"); + if ((event->flags & mir_key_flag_canceled) != 0) + g_printerr (" canceled"); + if ((event->flags & mir_key_flag_virtual_hard_key) != 0) + g_printerr (" virtual-hard-key"); + if ((event->flags & mir_key_flag_long_press) != 0) + g_printerr (" long-press"); + if ((event->flags & mir_key_flag_canceled_long_press) != 0) + g_printerr (" canceled-long-press"); + if ((event->flags & mir_key_flag_tracking) != 0) + g_printerr (" tracking"); + if ((event->flags & mir_key_flag_fallback) != 0) + g_printerr (" fallback"); + g_printerr ("\n"); + _gdk_mir_print_modifiers (event->modifiers); + g_printerr (" Key Code %i\n", event->key_code); + g_printerr (" Scan Code %i\n", event->scan_code); + g_printerr (" Repeat Count %i\n", event->repeat_count); + g_printerr (" Down Time %lli\n", (long long int) event->down_time); + g_printerr (" Event Time %lli\n", (long long int) event->event_time); + g_printerr (" Is System Key %s\n", event->is_system_key ? "true" : "false"); +} + +void +_gdk_mir_print_motion_event (const MirMotionEvent *event) +{ + size_t i; + + g_printerr ("MOTION\n"); + g_printerr (" Device %i\n", event->device_id); + g_printerr (" Source %i\n", event->source_id); + g_printerr (" Action "); + switch (event->action) + { + case mir_motion_action_down: + g_printerr ("down"); + break; + case mir_motion_action_up: + g_printerr ("up"); + break; + case mir_motion_action_move: + g_printerr ("move"); + break; + case mir_motion_action_cancel: + g_printerr ("cancel"); + break; + case mir_motion_action_outside: + g_printerr ("outside"); + break; + case mir_motion_action_pointer_down: + g_printerr ("pointer-down"); + break; + case mir_motion_action_pointer_up: + g_printerr ("pointer-up"); + break; + case mir_motion_action_hover_move: + g_printerr ("hover-move"); + break; + case mir_motion_action_scroll: + g_printerr ("scroll"); + break; + case mir_motion_action_hover_enter: + g_printerr ("hover-enter"); + break; + case mir_motion_action_hover_exit: + g_printerr ("hover-exit"); + break; + default: + g_printerr ("%u", event->action); + } + g_printerr ("\n"); + g_printerr (" Flags"); + switch (event->flags) + { + case mir_motion_flag_window_is_obscured: + g_printerr (" window-is-obscured"); + break; + } + g_printerr ("\n"); + _gdk_mir_print_modifiers (event->modifiers); + g_printerr (" Edge Flags %i\n", event->edge_flags); + g_printerr (" Button State"); + switch (event->button_state) + { + case mir_motion_button_primary: + g_printerr (" primary"); + break; + case mir_motion_button_secondary: + g_printerr (" secondary"); + break; + case mir_motion_button_tertiary: + g_printerr (" tertiary"); + break; + case mir_motion_button_back: + g_printerr (" back"); + break; + case mir_motion_button_forward: + g_printerr (" forward"); + break; + } + g_printerr ("\n"); + g_printerr (" Offset (%f, %f)\n", event->x_offset, event->y_offset); + g_printerr (" Precision (%f, %f)\n", event->x_precision, event->y_precision); + g_printerr (" Down Time %lli\n", (long long int) event->down_time); + g_printerr (" Event Time %lli\n", (long long int) event->event_time); + g_printerr (" Pointer Coordinates\n"); + for (i = 0; i < event->pointer_count; i++) + { + g_printerr (" ID=%i location=(%f, %f) raw=(%f, %f) touch=(%f, %f) size=%f pressure=%f orientation=%f scroll=(%f, %f) tool=", + event->pointer_coordinates[i].id, + event->pointer_coordinates[i].x, event->pointer_coordinates[i].y, + event->pointer_coordinates[i].raw_x, event->pointer_coordinates[i].raw_y, + event->pointer_coordinates[i].touch_major, event->pointer_coordinates[i].touch_minor, + event->pointer_coordinates[i].size, + event->pointer_coordinates[i].pressure, + event->pointer_coordinates[i].orientation, + event->pointer_coordinates[i].hscroll, event->pointer_coordinates[i].vscroll); + switch (event->pointer_coordinates[i].tool_type) + { + case mir_motion_tool_type_unknown: + g_printerr ("unknown"); + break; + case mir_motion_tool_type_finger: + g_printerr ("finger"); + break; + case mir_motion_tool_type_stylus: + g_printerr ("stylus"); + break; + case mir_motion_tool_type_mouse: + g_printerr ("mouse"); + break; + case mir_motion_tool_type_eraser: + g_printerr ("eraser"); + break; + default: + g_printerr ("%u", event->pointer_coordinates[i].tool_type); + break; + } + g_printerr ("\n"); + } +} + +void +_gdk_mir_print_surface_event (const MirSurfaceEvent *event) +{ + g_printerr ("SURFACE\n"); + g_printerr (" Surface %i\n", event->id); + g_printerr (" Attribute "); + switch (event->attrib) + { + case mir_surface_attrib_type: + g_printerr ("type"); + break; + case mir_surface_attrib_state: + g_printerr ("state"); + break; + case mir_surface_attrib_swapinterval: + g_printerr ("swapinterval"); + break; + case mir_surface_attrib_focus: + g_printerr ("focus"); + break; + default: + g_printerr ("%u", event->attrib); + break; + } + g_printerr ("\n"); + g_printerr (" Value %i\n", event->value); +} + +void +_gdk_mir_print_resize_event (const MirResizeEvent *event) +{ + g_printerr ("RESIZE\n"); + g_printerr (" Surface %i\n", event->surface_id); + g_printerr (" Size (%i, %i)\n", event->width, event->height); +} + +void +_gdk_mir_print_event (const MirEvent *event) +{ + switch (event->type) + { + case mir_event_type_key: + _gdk_mir_print_key_event (&event->key); + break; + case mir_event_type_motion: + _gdk_mir_print_motion_event (&event->motion); + break; + case mir_event_type_surface: + _gdk_mir_print_surface_event (&event->surface); + break; + case mir_event_type_resize: + _gdk_mir_print_resize_event (&event->resize); + break; + default: + g_printerr ("EVENT %u\n", event->type); + break; + } +} diff --git a/gdk/mir/gdkmir-private.h b/gdk/mir/gdkmir-private.h new file mode 100644 index 0000000000..268295b0ad --- /dev/null +++ b/gdk/mir/gdkmir-private.h @@ -0,0 +1,86 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __GDK_PRIVATE_MIR_H__ +#define __GDK_PRIVATE_MIR_H__ + +#include "gdkmir.h" +#include "gdkdisplay.h" +#include "gdkscreen.h" +#include "gdkdevicemanager.h" +#include "gdkkeys.h" +#include "gdkwindowimpl.h" + +typedef struct _GdkMirWindowImpl GdkMirWindowImpl; +typedef struct _GdkMirWindowReference GdkMirWindowReference; +typedef struct _GdkMirEventSource GdkMirEventSource; + +#define GDK_TYPE_MIR_WINDOW_IMPL (gdk_mir_window_impl_get_type ()) +#define GDK_MIR_WINDOW_IMPL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MIR_WINDOW_IMPL, GdkMirWindowImpl)) +#define GDK_IS_WINDOW_IMPL_MIR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_WINDOW_IMPL)) + +GType gdk_mir_window_impl_get_type (void); + +GdkDisplay *_gdk_mir_display_open (const gchar *display_name); + +GdkScreen *_gdk_mir_screen_new (GdkDisplay *display); + +GdkDeviceManager *_gdk_mir_device_manager_new (GdkDisplay *display); + +GdkDevice *_gdk_mir_device_manager_get_keyboard (GdkDeviceManager *device_manager); + +GdkKeymap *_gdk_mir_keymap_new (void); + +GdkDevice *_gdk_mir_keyboard_new (GdkDeviceManager *device_manager, const gchar *name); + +GdkDevice *_gdk_mir_pointer_new (GdkDeviceManager *device_manager, const gchar *name); + +void _gdk_mir_pointer_set_location (GdkDevice *pointer, gdouble x, gdouble y, GdkWindow *window, GdkModifierType mask); + +GdkCursor *_gdk_mir_cursor_new (GdkDisplay *display, GdkCursorType type); + +GdkWindowImpl *_gdk_mir_window_impl_new (void); + +void _gdk_mir_window_impl_set_surface_state (GdkMirWindowImpl *impl, MirSurfaceState state); + +void _gdk_mir_window_impl_set_cursor_state (GdkMirWindowImpl *impl, gdouble x, gdouble y, gboolean cursor_inside, MirMotionButton button_state); + +void _gdk_mir_window_impl_get_cursor_state (GdkMirWindowImpl *impl, gdouble *x, gdouble *y, gboolean *cursor_inside, MirMotionButton *button_state); + +GdkMirEventSource *_gdk_mir_display_get_event_source (GdkDisplay *display); + +GdkMirEventSource *_gdk_mir_event_source_new (GdkDisplay *display); + +GdkMirWindowReference *_gdk_mir_event_source_get_window_reference (GdkWindow *window); + +void _gdk_mir_window_reference_unref (GdkMirWindowReference *ref); + +void _gdk_mir_event_source_queue (GdkMirWindowReference *window_ref, const MirEvent *event); + +void _gdk_mir_print_modifiers (unsigned int modifiers); + +void _gdk_mir_print_key_event (const MirKeyEvent *event); + +void _gdk_mir_print_motion_event (const MirMotionEvent *event); + +void _gdk_mir_print_surface_event (const MirSurfaceEvent *event); + +void _gdk_mir_print_resize_event (const MirResizeEvent *event); + +void _gdk_mir_print_event (const MirEvent *event); + +#endif /* __GDK_PRIVATE_MIR_H__ */ diff --git a/gdk/mir/gdkmir.h b/gdk/mir/gdkmir.h new file mode 100644 index 0000000000..1ab0a2867a --- /dev/null +++ b/gdk/mir/gdkmir.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __GDK_MIR_H__ +#define __GDK_MIR_H__ + +#include +#include + +#define GDK_TYPE_MIR_DISPLAY (gdk_mir_display_get_type ()) +#define GDK_IS_MIR_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_DISPLAY)) + +#define GDK_TYPE_MIR_WINDOW (gdk_mir_window_get_type ()) +#define GDK_IS_WINDOW_MIR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WINDOW_MIR)) + +GDK_AVAILABLE_IN_3_10 +GType gdk_mir_display_get_type (void); + +GDK_AVAILABLE_IN_3_10 +struct MirConnection *gdk_mir_display_get_mir_connection (GdkDisplay *display); + +GDK_AVAILABLE_IN_3_10 +GType gdk_mir_window_get_type (void); + +#endif /* __GDK_MIR_H__ */ diff --git a/gdk/mir/gdkmircursor.c b/gdk/mir/gdkmircursor.c new file mode 100644 index 0000000000..bdbce5ea95 --- /dev/null +++ b/gdk/mir/gdkmircursor.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkcursorprivate.h" + +#include "gdkmir.h" +#include "gdkmir-private.h" + +typedef struct GdkMirCursor GdkMirCursor; +typedef struct GdkMirCursorClass GdkMirCursorClass; + +#define GDK_TYPE_MIR_CURSOR (gdk_mir_cursor_get_type ()) +#define GDK_MIR_CURSOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MIR_CURSOR, GdkMirCursor)) +#define GDK_MIR_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MIR_CURSOR, GdkMirCursorClass)) +#define GDK_IS_MIR_CURSOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_CURSOR)) +#define GDK_IS_MIR_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MIR_CURSOR)) +#define GDK_MIR_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MIR_CURSOR, GdkMirCursorClass)) + +struct GdkMirCursor +{ + GdkCursor parent_instance; +}; + +struct GdkMirCursorClass +{ + GdkCursorClass parent_class; +}; + +G_DEFINE_TYPE (GdkMirCursor, gdk_mir_cursor, GDK_TYPE_CURSOR) + +GdkCursor * +_gdk_mir_cursor_new (GdkDisplay *display, GdkCursorType type) +{ + return g_object_new (GDK_TYPE_MIR_CURSOR, "display", display, "cursor-type", type, NULL); +} + +cairo_surface_t * +gdk_mir_cursor_get_surface (GdkCursor *cursor, + gdouble *x_hot, + gdouble *y_hot) +{ + g_printerr ("gdk_mir_cursor_get_surface\n"); + return NULL; +} + +static void +gdk_mir_cursor_init (GdkMirCursor *cursor) +{ +} + +static void +gdk_mir_cursor_class_init (GdkMirCursorClass *klass) +{ + GdkCursorClass *cursor_class = GDK_CURSOR_CLASS (klass); + + cursor_class->get_surface = gdk_mir_cursor_get_surface; +} diff --git a/gdk/mir/gdkmirdevicemanager.c b/gdk/mir/gdkmirdevicemanager.c new file mode 100644 index 0000000000..c94f8a3ded --- /dev/null +++ b/gdk/mir/gdkmirdevicemanager.c @@ -0,0 +1,120 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkdevicemanagerprivate.h" +#include "gdkdisplayprivate.h" +#include "gdkdeviceprivate.h" + +#include "gdkmir.h" +#include "gdkmir-private.h" + +typedef struct GdkMirDeviceManager GdkMirDeviceManager; +typedef struct GdkMirDeviceManagerClass GdkMirDeviceManagerClass; + +#define GDK_TYPE_MIR_DEVICE_MANAGER (gdk_mir_device_manager_get_type ()) +#define GDK_MIR_DEVICE_MANAGER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MIR_DEVICE_MANAGER, GdkMirDeviceManager)) +#define GDK_MIR_DEVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MIR_DEVICE_MANAGER, GdkMirDeviceManagerClass)) +#define GDK_IS_MIR_DEVICE_MANAGER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_DEVICE_MANAGER)) +#define GDK_IS_MIR_DEVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MIR_DEVICE_MANAGER)) +#define GDK_MIR_DEVICE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MIR_DEVICE_MANAGER, GdkMirDeviceManagerClass)) + +struct GdkMirDeviceManager +{ + GdkDeviceManager parent_instance; + + GdkDevice *pointer; + GdkDevice *keyboard; +}; + +struct GdkMirDeviceManagerClass +{ + GdkDeviceManagerClass parent_class; +}; + +G_DEFINE_TYPE (GdkMirDeviceManager, gdk_mir_device_manager, GDK_TYPE_DEVICE_MANAGER) + +GdkDeviceManager * +_gdk_mir_device_manager_new (GdkDisplay *display) +{ + return g_object_new (GDK_TYPE_MIR_DEVICE_MANAGER, "display", display, NULL); +} + +static GList * +gdk_mir_device_manager_list_devices (GdkDeviceManager *device_manager, + GdkDeviceType type) +{ + //g_printerr ("gdk_mir_device_manager_list_devices (%u)\n", type); + GdkMirDeviceManager *dm = GDK_MIR_DEVICE_MANAGER (device_manager); + + if (type == GDK_DEVICE_TYPE_MASTER) + { + GList *devices; + + devices = g_list_append (NULL, dm->keyboard); + devices = g_list_append (devices, dm->pointer); + + return devices; + } + + return NULL; +} + +static GdkDevice * +gdk_mir_device_manager_get_client_pointer (GdkDeviceManager *device_manager) +{ + //g_printerr ("gdk_mir_device_manager_get_client_pointer\n"); + return GDK_MIR_DEVICE_MANAGER (device_manager)->pointer; +} + +GdkDevice * +_gdk_mir_device_manager_get_keyboard (GdkDeviceManager *device_manager) +{ + return GDK_MIR_DEVICE_MANAGER (device_manager)->keyboard; +} + +static void +gdk_mir_device_manager_init (GdkMirDeviceManager *device_manager) +{ +} + +static void +gdk_mir_device_manager_constructed (GObject *object) +{ + GdkMirDeviceManager *device_manager = GDK_MIR_DEVICE_MANAGER (object); + + device_manager->keyboard = _gdk_mir_keyboard_new (GDK_DEVICE_MANAGER (device_manager), "Mir Keyboard"); + device_manager->pointer = _gdk_mir_pointer_new (GDK_DEVICE_MANAGER (device_manager), "Mir Pointer"); + _gdk_device_set_associated_device (device_manager->keyboard, device_manager->pointer); + _gdk_device_set_associated_device (device_manager->pointer, device_manager->keyboard); + + gdk_device_manager_get_display (GDK_DEVICE_MANAGER (device_manager))->core_pointer = device_manager->pointer; + + G_OBJECT_CLASS (gdk_mir_device_manager_parent_class)->constructed (object); +} + +static void +gdk_mir_device_manager_class_init (GdkMirDeviceManagerClass *klass) +{ + GdkDeviceManagerClass *device_manager_class = GDK_DEVICE_MANAGER_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + device_manager_class->list_devices = gdk_mir_device_manager_list_devices; + device_manager_class->get_client_pointer = gdk_mir_device_manager_get_client_pointer; + object_class->constructed = gdk_mir_device_manager_constructed; +} diff --git a/gdk/mir/gdkmirdisplay.c b/gdk/mir/gdkmirdisplay.c new file mode 100644 index 0000000000..92dfceefd5 --- /dev/null +++ b/gdk/mir/gdkmirdisplay.c @@ -0,0 +1,572 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkdisplayprivate.h" +#include "gdkinternals.h" + +#include "gdkmir.h" +#include "gdkmir-private.h" + +#define GDK_TYPE_DISPLAY_MIR (gdk_mir_display_get_type ()) +#define GDK_MIR_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_DISPLAY_MIR, GdkMirDisplay)) +#define GDK_MIR_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_DISPLAY_MIR, GdkMirDisplayClass)) +#define GDK_IS_MIR_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MIR_DISPLAY)) +#define GDK_MIR_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MIR_DISPLAY, GdkMirDisplayImplClass)) + +typedef struct GdkMirDisplay +{ + GdkDisplay parent_instance; + + /* Connection to Mir server */ + MirConnection *connection; + + /* Event source */ + GdkMirEventSource *event_source; + + /* Serial number? */ + gulong serial; + + /* Screen information */ + GdkScreen *screen; + + GdkCursor *cursor; + + GdkKeymap *keymap; +} GdkMirDisplay; + +typedef struct GdkMirDisplayClass +{ + GdkDisplayClass parent_class; +} GdkMirDisplayClass; + +/** + * SECTION:mir_interaction + * @Short_description: Mir backend-specific functions + * @Title: Mir Interaction + * + * The functions in this section are specific to the GDK Mir backend. + * To use them, you need to include the <gdk/gdkmir.h> + * header and use the Mir-specific pkg-config files to build your + * application (either gdk-mir-3.0 or + * gtk+-mir-3.0). + * + * To make your code compile with other GDK backends, guard backend-specific + * calls by an ifdef as follows. Since GDK may be built with multiple + * backends, you should also check for the backend that is in use (e.g. by + * using the GDK_IS_MIR_DISPLAY() macro). + * |[ + * #ifdef GDK_WINDOWING_MIR + * if (GDK_IS_MIR_DISPLAY (display)) + * { + * /* make Mir-specific calls here */ + * } + * else + * #endif + * #ifdef GDK_WINDOWING_X11 + * if (GDK_IS_X11_DISPLAY (display)) + * { + * /* make X11-specific calls here */ + * } + * else + * #endif + * g_error ("Unsupported GDK backend"); + * ]| + */ + +G_DEFINE_TYPE (GdkMirDisplay, gdk_mir_display, GDK_TYPE_DISPLAY) + +GdkDisplay * +_gdk_mir_display_open (const gchar *display_name) +{ + MirConnection *connection; + GdkMirDisplay *display; + + g_printerr ("gdk_mir_display_open\n"); + + connection = mir_connect_sync (NULL, "GDK-Mir"); + if (!connection) + return NULL; + if (!mir_connection_is_valid (connection)) + { + g_printerr ("Failed to connect to Mir: %s\n", mir_connection_get_error_message (connection)); + mir_connection_release (connection); + return NULL; + } + + display = g_object_new (GDK_TYPE_MIR_DISPLAY, NULL); + + display->connection = connection; + GDK_DISPLAY (display)->device_manager = _gdk_mir_device_manager_new (GDK_DISPLAY (display)); + display->screen = _gdk_mir_screen_new (GDK_DISPLAY (display)); + + g_signal_emit_by_name (display, "opened"); + + return GDK_DISPLAY (display); +} + +/** + * gdk_mir_display_get_mir_connection + * @display: (type GdkMirDisplay): a #GdkDisplay + * + * Returns the #MirConnection for a #GdkDisplay + * + * Returns: (transfer none): a #MirConnection + * + * Since: 3.14 + */ +struct MirConnection * +gdk_mir_display_get_mir_connection (GdkDisplay *display) +{ + g_return_val_if_fail (GDK_IS_MIR_DISPLAY (display), NULL); + return GDK_MIR_DISPLAY (display)->connection; +} + +GdkMirEventSource * +_gdk_mir_display_get_event_source (GdkDisplay *display) +{ + g_return_val_if_fail (GDK_IS_MIR_DISPLAY (display), NULL); + + return GDK_MIR_DISPLAY (display)->event_source; +} + +static void +gdk_mir_display_dispose (GObject *object) +{ + GdkMirDisplay *display = GDK_MIR_DISPLAY (object); + + g_object_unref (display->screen); + display->screen = NULL; + + G_OBJECT_CLASS (gdk_mir_display_parent_class)->dispose (object); +} + +static void +gdk_mir_display_finalize (GObject *object) +{ + GdkMirDisplay *display = GDK_MIR_DISPLAY (object); + + mir_connection_release (display->connection); + + G_OBJECT_CLASS (gdk_mir_display_parent_class)->finalize (object); +} + +static const gchar * +gdk_mir_display_get_name (GdkDisplay *display) +{ + //g_printerr ("gdk_mir_display_get_name\n"); + return "Mir"; +} + +static GdkScreen * +gdk_mir_display_get_default_screen (GdkDisplay *display) +{ + //g_printerr ("gdk_mir_display_get_default_screen\n"); + return GDK_MIR_DISPLAY (display)->screen; +} + +static void +gdk_mir_display_beep (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_beep\n"); + /* No system level beep... */ +} + +static void +gdk_mir_display_sync (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_sync\n"); +} + +static void +gdk_mir_display_flush (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_flush\n"); +} + +static gboolean +gdk_mir_display_has_pending (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_has_pending\n"); + /* We don't need to poll for events - so nothing pending */ + return FALSE; +} + +static void +gdk_mir_display_queue_events (GdkDisplay *display) +{ + //g_printerr ("gdk_mir_display_queue_events\n"); + /* We don't need to poll for events - so don't do anything*/ +} + +static void +gdk_mir_display_make_default (GdkDisplay *display) +{ + //g_printerr ("gdk_mir_display_make_default\n"); +} + +static GdkWindow * +gdk_mir_display_get_default_group (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_get_default_group\n"); + return NULL; +} + +static gboolean +gdk_mir_display_supports_shapes (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_supports_shapes\n"); + /* Mir doesn't support shaped windows */ + return FALSE; +} + +static gboolean +gdk_mir_display_supports_input_shapes (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_supports_input_shapes\n"); + return FALSE; +} + +static gboolean +gdk_mir_display_supports_composite (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_supports_composite\n"); + return FALSE; +} + +static gboolean +gdk_mir_display_supports_clipboard_persistence (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_supports_clipboard_persistence\n"); + return FALSE; +} + +static gboolean +gdk_mir_display_supports_cursor_alpha (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_supports_cursor_alpha\n"); + return FALSE; +} + +static gboolean +gdk_mir_display_supports_cursor_color (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_supports_cursor_color\n"); + return FALSE; +} + +static gboolean +gdk_mir_display_supports_selection_notification (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_supports_selection_notification\n"); + return FALSE; +} + +static gboolean +gdk_mir_display_request_selection_notification (GdkDisplay *display, + GdkAtom selection) +{ + g_printerr ("gdk_mir_display_request_selection_notification\n"); + return FALSE; +} + +static void +gdk_mir_display_store_clipboard (GdkDisplay *display, + GdkWindow *clipboard_window, + guint32 time_, + const GdkAtom *targets, + gint n_targets) +{ + g_printerr ("gdk_mir_display_store_clipboard\n"); +} + +static void +gdk_mir_display_get_default_cursor_size (GdkDisplay *display, + guint *width, + guint *height) +{ + g_printerr ("gdk_mir_display_get_default_cursor_size\n"); + *width = *height = 32; // FIXME: Random value +} + +static void +gdk_mir_display_get_maximal_cursor_size (GdkDisplay *display, + guint *width, + guint *height) +{ + g_printerr ("gdk_mir_display_get_maximal_cursor_size\n"); + *width = *height = 32; // FIXME: Random value +} + +static GdkCursor * +gdk_mir_display_get_cursor_for_type (GdkDisplay *display, + GdkCursorType cursor_type) +{ + //g_printerr ("gdk_mir_display_get_cursor_for_type (%u)\n", cursor_type); + /* We don't support configurable cursors */ + return g_object_ref (GDK_MIR_DISPLAY (display)->cursor); +} + +static GdkCursor * +gdk_mir_display_get_cursor_for_name (GdkDisplay *display, + const gchar *name) +{ + g_printerr ("gdk_mir_display_get_cursor_for_name (\"%s\")\n", name); + /* We don't support configurable cursors */ + return g_object_ref (GDK_MIR_DISPLAY (display)->cursor); +} + +static GdkCursor * +gdk_mir_display_get_cursor_for_surface (GdkDisplay *display, + cairo_surface_t *surface, + gdouble x, + gdouble y) +{ + g_printerr ("gdk_mir_display_get_cursor_for_surface (%f, %f)\n", x, y); + return NULL; +} + +static GList * +gdk_mir_display_list_devices (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_list_devices\n"); + // FIXME: Should this access the device manager? + return NULL; +} + +static GdkAppLaunchContext * +gdk_mir_display_get_app_launch_context (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_get_app_launch_context\n"); + return NULL; +} + +static void +gdk_mir_display_before_process_all_updates (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_before_process_all_updates\n"); +} + +static void +gdk_mir_display_after_process_all_updates (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_after_process_all_updates\n"); +} + +static gulong +gdk_mir_display_get_next_serial (GdkDisplay *display) +{ + //g_printerr ("gdk_mir_display_get_next_serial\n"); + return GDK_MIR_DISPLAY (display)->serial++; +} + +static void +gdk_mir_display_notify_startup_complete (GdkDisplay *display, + const gchar *startup_id) +{ + //g_printerr ("gdk_mir_display_notify_startup_complete\n"); +} + +static void +gdk_mir_display_event_data_copy (GdkDisplay *display, + const GdkEvent *src, + GdkEvent *dst) +{ + //g_printerr ("gdk_mir_display_event_data_copy\n"); +} + +static void +gdk_mir_display_event_data_free (GdkDisplay *display, + GdkEvent *event) +{ + //g_printerr ("gdk_mir_display_event_data_free\n"); +} + +static void +gdk_mir_display_create_window_impl (GdkDisplay *display, + GdkWindow *window, + GdkWindow *real_parent, + GdkScreen *screen, + GdkEventMask event_mask, + GdkWindowAttr *attributes, + gint attributes_mask) +{ + g_printerr ("gdk_mir_display_create_window_impl"); + g_printerr (" window=%p", window); + g_printerr (" location=(%d, %d)", window->x, window->y); + g_printerr (" size=(%d, %d)", window->width, window->height); + g_printerr ("\n"); + if (attributes->wclass != GDK_INPUT_OUTPUT) + return; + window->impl = _gdk_mir_window_impl_new (); +} + +static GdkKeymap * +gdk_mir_display_get_keymap (GdkDisplay *display) +{ + //g_printerr ("gdk_mir_display_get_keymap\n"); + return GDK_MIR_DISPLAY (display)->keymap; +} + +static void +gdk_mir_display_push_error_trap (GdkDisplay *display) +{ + g_printerr ("gdk_mir_display_push_error_trap\n"); +} + +static gint +gdk_mir_display_pop_error_trap (GdkDisplay *display, + gboolean ignored) +{ + g_printerr ("gdk_mir_display_pop_error_trap\n"); + return 0; +} + +static GdkWindow * +gdk_mir_display_get_selection_owner (GdkDisplay *display, + GdkAtom selection) +{ + g_printerr ("gdk_mir_display_get_selection_owner\n"); + return NULL; +} + +static gboolean +gdk_mir_display_set_selection_owner (GdkDisplay *display, + GdkWindow *owner, + GdkAtom selection, + guint32 time, + gboolean send_event) +{ + g_printerr ("gdk_mir_display_set_selection_owner\n"); + return FALSE; +} + +static void +gdk_mir_display_send_selection_notify (GdkDisplay *display, + GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + GdkAtom property, + guint32 time) +{ + g_printerr ("gdk_mir_display_send_selection_notify\n"); +} + +static gint +gdk_mir_display_get_selection_property (GdkDisplay *display, + GdkWindow *requestor, + guchar **data, + GdkAtom *ret_type, + gint *ret_format) +{ + g_printerr ("gdk_mir_display_get_selection_property\n"); + return 0; +} + +static void +gdk_mir_display_convert_selection (GdkDisplay *display, + GdkWindow *requestor, + GdkAtom selection, + GdkAtom target, + guint32 time) +{ + g_printerr ("gdk_mir_display_convert_selection\n"); +} + +static gint +gdk_mir_display_text_property_to_utf8_list (GdkDisplay *display, + GdkAtom encoding, + gint format, + const guchar *text, + gint length, + gchar ***list) +{ + g_printerr ("gdk_mir_display_text_property_to_utf8_list\n"); + return 0; +} + +static gchar * +gdk_mir_display_utf8_to_string_target (GdkDisplay *display, + const gchar *str) +{ + g_printerr ("gdk_mir_display_utf8_to_string_target\n"); + return NULL; +} + +static void +gdk_mir_display_init (GdkMirDisplay *display) +{ + display->event_source = _gdk_mir_event_source_new (GDK_DISPLAY (display)); + display->cursor = _gdk_mir_cursor_new (GDK_DISPLAY (display), GDK_ARROW); + display->keymap = _gdk_mir_keymap_new (); +} + +static void +gdk_mir_display_class_init (GdkMirDisplayClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (klass); + + object_class->dispose = gdk_mir_display_dispose; + object_class->finalize = gdk_mir_display_finalize; + + display_class->window_type = gdk_mir_window_get_type (); + + display_class->get_name = gdk_mir_display_get_name; + display_class->get_default_screen = gdk_mir_display_get_default_screen; + display_class->beep = gdk_mir_display_beep; + display_class->sync = gdk_mir_display_sync; + display_class->flush = gdk_mir_display_flush; + display_class->has_pending = gdk_mir_display_has_pending; + display_class->queue_events = gdk_mir_display_queue_events; + display_class->make_default = gdk_mir_display_make_default; + display_class->get_default_group = gdk_mir_display_get_default_group; + display_class->supports_shapes = gdk_mir_display_supports_shapes; + display_class->supports_input_shapes = gdk_mir_display_supports_input_shapes; + display_class->supports_composite = gdk_mir_display_supports_composite; + display_class->supports_clipboard_persistence = gdk_mir_display_supports_clipboard_persistence; + display_class->supports_cursor_alpha = gdk_mir_display_supports_cursor_alpha; + display_class->supports_cursor_color = gdk_mir_display_supports_cursor_color; + display_class->supports_selection_notification = gdk_mir_display_supports_selection_notification; + display_class->request_selection_notification = gdk_mir_display_request_selection_notification; + display_class->store_clipboard = gdk_mir_display_store_clipboard; + display_class->get_default_cursor_size = gdk_mir_display_get_default_cursor_size; + display_class->get_maximal_cursor_size = gdk_mir_display_get_maximal_cursor_size; + display_class->get_cursor_for_type = gdk_mir_display_get_cursor_for_type; + display_class->get_cursor_for_name = gdk_mir_display_get_cursor_for_name; + display_class->get_cursor_for_surface = gdk_mir_display_get_cursor_for_surface; + display_class->list_devices = gdk_mir_display_list_devices; + display_class->get_app_launch_context = gdk_mir_display_get_app_launch_context; + display_class->before_process_all_updates = gdk_mir_display_before_process_all_updates; + display_class->after_process_all_updates = gdk_mir_display_after_process_all_updates; + display_class->get_next_serial = gdk_mir_display_get_next_serial; + display_class->notify_startup_complete = gdk_mir_display_notify_startup_complete; + display_class->event_data_copy = gdk_mir_display_event_data_copy; + display_class->event_data_free = gdk_mir_display_event_data_free; + display_class->create_window_impl = gdk_mir_display_create_window_impl; + display_class->get_keymap = gdk_mir_display_get_keymap; + display_class->push_error_trap = gdk_mir_display_push_error_trap; + display_class->pop_error_trap = gdk_mir_display_pop_error_trap; + display_class->get_selection_owner = gdk_mir_display_get_selection_owner; + display_class->set_selection_owner = gdk_mir_display_set_selection_owner; + display_class->send_selection_notify = gdk_mir_display_send_selection_notify; + display_class->get_selection_property = gdk_mir_display_get_selection_property; + display_class->convert_selection = gdk_mir_display_convert_selection; + display_class->text_property_to_utf8_list = gdk_mir_display_text_property_to_utf8_list; + display_class->utf8_to_string_target = gdk_mir_display_utf8_to_string_target; +} diff --git a/gdk/mir/gdkmireventsource.c b/gdk/mir/gdkmireventsource.c new file mode 100644 index 0000000000..7396eba8b1 --- /dev/null +++ b/gdk/mir/gdkmireventsource.c @@ -0,0 +1,624 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkinternals.h" +#include "gdkdisplayprivate.h" +#include "gdkmir.h" +#include "gdkmir-private.h" + +struct _GdkMirWindowReference { + GdkMirEventSource *source; + GdkWindow *window; + gint ref_count; +}; + +typedef struct { + GdkMirWindowReference *window_ref; + MirEvent event; +} GdkMirQueuedEvent; + +struct _GdkMirEventSource +{ + GSource parent_instance; + + GMutex mir_event_lock; + GQueue mir_events; + + GdkDisplay *display; +}; + +static void +send_event (GdkWindow *window, GdkDevice *device, GdkEvent *event) +{ + GdkDisplay *display; + GList *node; + + gdk_event_set_device (event, device); + gdk_event_set_screen (event, gdk_display_get_screen (gdk_window_get_display (window), 0)); + event->any.window = g_object_ref (window); + + display = gdk_window_get_display (window); + node = _gdk_event_queue_append (display, event); + _gdk_windowing_got_event (display, node, event, _gdk_display_get_next_serial (display)); +} + +static void +set_key_event_string (GdkEventKey *event) +{ + gunichar c = 0; + + if (event->keyval != GDK_KEY_VoidSymbol) + c = gdk_keyval_to_unicode (event->keyval); + + if (c) + { + gchar buf[7]; + gint len; + gsize bytes_written; + + /* Apply the control key - Taken from Xlib + */ + if (event->state & GDK_CONTROL_MASK) + { + if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F; + else if (c == '2') + { + event->string = g_memdup ("\0\0", 2); + event->length = 1; + buf[0] = '\0'; + return; + } + else if (c >= '3' && c <= '7') c -= ('3' - '\033'); + else if (c == '8') c = '\177'; + else if (c == '/') c = '_' & 0x1F; + } + + len = g_unichar_to_utf8 (c, buf); + buf[len] = '\0'; + + event->string = g_locale_from_utf8 (buf, len, + NULL, &bytes_written, + NULL); + if (event->string) + event->length = bytes_written; + } + else if (event->keyval == GDK_KEY_Escape) + { + event->length = 1; + event->string = g_strdup ("\033"); + } + else if (event->keyval == GDK_KEY_Return || + event->keyval == GDK_KEY_KP_Enter) + { + event->length = 1; + event->string = g_strdup ("\r"); + } + + if (!event->string) + { + event->length = 0; + event->string = g_strdup (""); + } +} + +static void +generate_key_event (GdkWindow *window, GdkEventType type, guint state, guint keyval, guint16 keycode, gboolean is_modifier) +{ + GdkEvent *event; + + event = gdk_event_new (type); + event->key.state = state; + event->key.keyval = keyval; + event->key.hardware_keycode = keycode + 8; + event->key.is_modifier = is_modifier; + set_key_event_string (&event->key); + + send_event (window, _gdk_mir_device_manager_get_keyboard (gdk_display_get_device_manager (gdk_window_get_display (window))), event); +} + +static GdkDevice * +get_pointer (GdkWindow *window) +{ + return gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (gdk_window_get_display (window))); +} + +static void +generate_button_event (GdkWindow *window, GdkEventType type, gdouble x, gdouble y, guint button, guint state) +{ + GdkEvent *event; + + event = gdk_event_new (type); + event->button.x = x; + event->button.y = y; + event->button.state = state; + event->button.button = button; + + send_event (window, get_pointer (window), event); +} + +static void +generate_scroll_event (GdkWindow *window, gdouble x, gdouble y, gdouble delta_x, gdouble delta_y, guint state) +{ + GdkEvent *event; + + event = gdk_event_new (GDK_SCROLL); + event->scroll.x = x; + event->scroll.y = y; + event->scroll.state = state; + event->scroll.direction = GDK_SCROLL_SMOOTH; + event->scroll.delta_x = delta_x; + event->scroll.delta_y = delta_y; + + send_event (window, get_pointer (window), event); +} + +static void +generate_motion_event (GdkWindow *window, gdouble x, gdouble y, guint state) +{ + GdkEvent *event; + + event = gdk_event_new (GDK_MOTION_NOTIFY); + event->motion.x = x; + event->motion.y = y; + event->motion.state = state; + event->motion.is_hint = FALSE; + + send_event (window, get_pointer (window), event); +} + +static void +generate_crossing_event (GdkWindow *window, GdkEventType type, gdouble x, gdouble y) +{ + GdkEvent *event; + + event = gdk_event_new (type); + event->crossing.x = x; + event->crossing.y = y; + event->crossing.mode = GDK_CROSSING_NORMAL; + event->crossing.detail = GDK_NOTIFY_ANCESTOR; + event->crossing.focus = TRUE; + + send_event (window, get_pointer (window), event); +} + +static void +generate_focus_event (GdkWindow *window, gboolean focused) +{ + GdkEvent *event; + + if (focused) + gdk_synthesize_window_state (window, 0, GDK_WINDOW_STATE_FOCUSED); + else + gdk_synthesize_window_state (window, GDK_WINDOW_STATE_FOCUSED, 0); + + event = gdk_event_new (GDK_FOCUS_CHANGE); + event->focus_change.send_event = FALSE; + event->focus_change.in = focused; + + send_event (window, get_pointer (window), event); +} + +static guint +get_modifier_state (unsigned int modifiers, unsigned int button_state) +{ + guint modifier_state = 0; + + if ((modifiers & mir_key_modifier_alt) != 0) + modifier_state |= GDK_MOD1_MASK; + if ((modifiers & mir_key_modifier_shift) != 0) + modifier_state |= GDK_SHIFT_MASK; + if ((modifiers & mir_key_modifier_ctrl) != 0) + modifier_state |= GDK_CONTROL_MASK; + if ((modifiers & mir_key_modifier_meta) != 0) + modifier_state |= GDK_SUPER_MASK; + if ((modifiers & mir_key_modifier_caps_lock) != 0) + modifier_state |= GDK_LOCK_MASK; + if ((button_state & mir_motion_button_primary) != 0) + modifier_state |= GDK_BUTTON1_MASK; + if ((button_state & mir_motion_button_secondary) != 0) + modifier_state |= GDK_BUTTON3_MASK; + if ((button_state & mir_motion_button_tertiary) != 0) + modifier_state |= GDK_BUTTON2_MASK; + + return modifier_state; +} + +/* + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (event_data->window->impl); + MirMotionButton changed_button_state; + GdkEventType event_type; + gdouble x, y; + guint modifier_state; + gboolean is_modifier = FALSE; +*/ + +static void +handle_key_event (GdkWindow *window, const MirKeyEvent *event) +{ + guint modifier_state; + gboolean is_modifier = FALSE; + + modifier_state = get_modifier_state (event->modifiers, 0); // FIXME: Need to track button state + + switch (event->action) + { + case mir_key_action_down: + case mir_key_action_up: + // FIXME: Convert keycode + // FIXME: is_modifier + generate_key_event (window, + event->action == mir_key_action_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE, + modifier_state, + event->key_code, + event->scan_code, + is_modifier); + break; + default: + //case mir_key_action_multiple: + // FIXME + break; + } +} + +static void +handle_motion_event (GdkWindow *window, const MirMotionEvent *event) +{ + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + gdouble x, y; + gboolean cursor_inside; + MirMotionButton button_state; + guint modifier_state; + GdkEventType event_type; + MirMotionButton changed_button_state; + + _gdk_mir_window_impl_get_cursor_state (impl, &x, &y, &cursor_inside, &button_state); + if (event->pointer_count > 0) + { + x = event->pointer_coordinates[0].x; + y = event->pointer_coordinates[0].y; + } + modifier_state = get_modifier_state (event->modifiers, event->button_state); + + /* The Mir events generate hover-exits even while inside the window so + counteract this by always generating an enter notify on all other events */ + if (!cursor_inside && event->action != mir_motion_action_hover_exit) + { + cursor_inside = TRUE; + generate_crossing_event (window, GDK_ENTER_NOTIFY, x, y); + } + + /* Update which window has focus */ + _gdk_mir_pointer_set_location (get_pointer (window), x, y, window, modifier_state); + switch (event->action) + { + case mir_motion_action_down: + case mir_motion_action_up: + event_type = event->action == mir_motion_action_down ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE; + changed_button_state = button_state ^ event->button_state; + if ((changed_button_state & mir_motion_button_primary) != 0) + generate_button_event (window, event_type, x, y, GDK_BUTTON_PRIMARY, modifier_state); + if ((changed_button_state & mir_motion_button_secondary) != 0) + generate_button_event (window, event_type, x, y, GDK_BUTTON_SECONDARY, modifier_state); + if ((changed_button_state & mir_motion_button_tertiary) != 0) + generate_button_event (window, event_type, x, y, GDK_BUTTON_MIDDLE, modifier_state); + button_state = event->button_state; + break; + case mir_motion_action_scroll: + generate_scroll_event (window, x, y, event->pointer_coordinates[0].hscroll, event->pointer_coordinates[0].vscroll, modifier_state); + break; + case mir_motion_action_move: // move with button + case mir_motion_action_hover_move: // move without button + generate_motion_event (window, x, y, modifier_state); + break; + case mir_motion_action_hover_exit: + cursor_inside = FALSE; + generate_crossing_event (window, GDK_LEAVE_NOTIFY, x, y); + break; + } + + _gdk_mir_window_impl_set_cursor_state (impl, x, y, cursor_inside, button_state); +} + +static void +handle_surface_event (GdkWindow *window, const MirSurfaceEvent *event) +{ + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + + switch (event->attrib) + { + case mir_surface_attrib_type: + break; + case mir_surface_attrib_state: + _gdk_mir_window_impl_set_surface_state (impl, event->value); + // FIXME: notify + break; + case mir_surface_attrib_swapinterval: + break; + case mir_surface_attrib_focus: + generate_focus_event (window, event->value != 0); + break; + default: + break; + } +} + +static void +generate_configure_event (GdkWindow *window, + gint width, + gint height) +{ + GdkEvent *event; + + event = gdk_event_new (GDK_CONFIGURE); + event->configure.send_event = FALSE; + event->configure.width = width; + event->configure.height = height; + + send_event (window, get_pointer (window), event); +} + +static void +handle_resize_event (GdkWindow *window, + const MirResizeEvent *event) +{ + window->width = event->width; + window->height = event->height; + _gdk_window_update_size (window); + + generate_configure_event (window, event->width, event->height); +} + +typedef struct +{ + GdkWindow *window; + MirEvent event; +} EventData; + +static void +gdk_mir_event_source_queue_event (GdkDisplay *display, + GdkWindow *window, + const MirEvent *event) +{ + if (g_getenv ("GDK_MIR_LOG_EVENTS")) + _gdk_mir_print_event (event); + + // FIXME: Only generate events if the window wanted them? + switch (event->type) + { + case mir_event_type_key: + handle_key_event (window, &event->key); + break; + case mir_event_type_motion: + handle_motion_event (window, &event->motion); + break; + case mir_event_type_surface: + handle_surface_event (window, &event->surface); + break; + case mir_event_type_resize: + handle_resize_event (window, &event->resize); + break; + default: + g_assert_not_reached (); + // FIXME? + break; + } +} + +static GdkMirQueuedEvent * +gdk_mir_event_source_take_queued_event (GdkMirEventSource *source) +{ + GdkMirQueuedEvent *queued_event; + + g_mutex_lock (&source->mir_event_lock); + queued_event = g_queue_pop_head (&source->mir_events); + g_mutex_unlock (&source->mir_event_lock); + + return queued_event; +} + +static void +gdk_mir_queued_event_free (GdkMirQueuedEvent *event) +{ + _gdk_mir_window_reference_unref (event->window_ref); + g_slice_free (GdkMirQueuedEvent, event); +} + +static void +gdk_mir_event_source_convert_events (GdkMirEventSource *source) +{ + GdkMirQueuedEvent *event; + + while ((event = gdk_mir_event_source_take_queued_event (source))) + { + GdkWindow *window = event->window_ref->window; + + /* The window may have been destroyed in the main thread while the + * event was being dispatched... + */ + if (window != NULL) + gdk_mir_event_source_queue_event (source->display, window, &event->event); + else + g_warning ("window was destroyed before event arrived..."); + + gdk_mir_queued_event_free (event); + } +} + +static gboolean +gdk_mir_event_source_prepare (GSource *g_source, + gint *timeout) +{ + GdkMirEventSource *source = (GdkMirEventSource *) g_source; + gboolean mir_events_in_queue; + + if (_gdk_event_queue_find_first (source->display)) + return TRUE; + + g_mutex_lock (&source->mir_event_lock); + mir_events_in_queue = g_queue_get_length (&source->mir_events) > 0; + g_mutex_unlock (&source->mir_event_lock); + + return mir_events_in_queue; +} + +static gboolean +gdk_mir_event_source_check (GSource *g_source) +{ + return gdk_mir_event_source_prepare (g_source, NULL); +} + +static gboolean +gdk_mir_event_source_dispatch (GSource *g_source, + GSourceFunc callback, + gpointer user_data) +{ + GdkMirEventSource *source = (GdkMirEventSource *) g_source; + GdkEvent *event; + + /* First, run the queue of events from the thread */ + gdk_mir_event_source_convert_events (source); + + /* Next, dispatch one single event from the display's queue. + * + * If there is more than one event then we will soon find ourselves + * back here again. + */ + + gdk_threads_enter (); + + event = gdk_display_get_event (source->display); + + if (event) + { + _gdk_event_emit (event); + + gdk_event_free (event); + } + + gdk_threads_leave (); + + return TRUE; +} + +static void +gdk_mir_event_source_finalize (GSource *g_source) +{ + GdkMirEventSource *source = (GdkMirEventSource *) g_source; + GdkMirQueuedEvent *event; + + while ((event = gdk_mir_event_source_take_queued_event (source))) + gdk_mir_queued_event_free (event); + + g_mutex_clear (&source->mir_event_lock); +} + +static GSourceFuncs gdk_mir_event_source_funcs = { + gdk_mir_event_source_prepare, + gdk_mir_event_source_check, + gdk_mir_event_source_dispatch, + gdk_mir_event_source_finalize +}; + +GdkMirEventSource * +_gdk_mir_event_source_new (GdkDisplay *display) +{ + GdkMirEventSource *source; + GSource *g_source; + + g_source = g_source_new (&gdk_mir_event_source_funcs, sizeof (GdkMirEventSource)); + g_source_attach (g_source, NULL); + + source = (GdkMirEventSource *) g_source; + g_mutex_init (&source->mir_event_lock); + source->display = display; + + return source; +} + +GdkMirWindowReference * +_gdk_mir_event_source_get_window_reference (GdkWindow *window) +{ + static GQuark win_ref_quark; + GdkMirWindowReference *ref; + + if G_UNLIKELY (!win_ref_quark) + win_ref_quark = g_quark_from_string ("GdkMirEventSource window reference"); + + ref = g_object_get_qdata (G_OBJECT (window), win_ref_quark); + + if (!ref) + { + GdkMirEventSource *source; + + source = _gdk_mir_display_get_event_source (gdk_window_get_display (window)); + g_source_ref ((GSource *) source); + + ref = g_slice_new (GdkMirWindowReference); + ref->window = window; + ref->source = source; + ref->ref_count = 0; + g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &ref->window); + + g_object_set_qdata_full (G_OBJECT (window), win_ref_quark, + ref, (GDestroyNotify) _gdk_mir_window_reference_unref); + } + + g_atomic_int_inc (&ref->ref_count); + + return ref; +} + +void +_gdk_mir_window_reference_unref (GdkMirWindowReference *ref) +{ + if (g_atomic_int_dec_and_test (&ref->ref_count)) + { + if (ref->window) + g_object_remove_weak_pointer (G_OBJECT (ref->window), (gpointer *) &ref->window); + + g_source_unref ((GSource *) ref->source); + + g_slice_free (GdkMirWindowReference, ref); + } +} + +void +_gdk_mir_event_source_queue (GdkMirWindowReference *window_ref, + const MirEvent *event) +{ + GdkMirEventSource *source = window_ref->source; + GdkMirQueuedEvent *queued_event; + + /* We are in the wrong thread right now. We absolutely cannot touch + * the window. + * + * We can do pretty much anything we want with the source, though... + */ + + queued_event = g_slice_new (GdkMirQueuedEvent); + g_atomic_int_inc (&window_ref->ref_count); + queued_event->window_ref = window_ref; + queued_event->event = *event; + + g_mutex_lock (&source->mir_event_lock); + g_queue_push_tail (&source->mir_events, queued_event); + g_mutex_unlock (&source->mir_event_lock); + + g_main_context_wakeup (NULL); +} diff --git a/gdk/mir/gdkmirkeyboard.c b/gdk/mir/gdkmirkeyboard.c new file mode 100644 index 0000000000..86c0d9f4ea --- /dev/null +++ b/gdk/mir/gdkmirkeyboard.c @@ -0,0 +1,173 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkdeviceprivate.h" + +typedef struct GdkMirKeyboard GdkMirKeyboard; +typedef struct GdkMirKeyboardClass GdkMirKeyboardClass; + +#define GDK_TYPE_MIR_KEYBOARD (gdk_mir_keyboard_get_type ()) +#define GDK_MIR_KEYBOARD(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MIR_KEYBOARD, GdkMirKeyboard)) +#define GDK_MIR_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MIR_KEYBOARD, GdkMirKeyboardClass)) +#define GDK_IS_MIR_KEYBOARD(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_KEYBOARD)) +#define GDK_IS_MIR_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MIR_KEYBOARD)) +#define GDK_MIR_KEYBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MIR_KEYBOARD, GdkMirKeyboardClass)) + +struct GdkMirKeyboard +{ + GdkDevice parent_instance; +}; + +struct GdkMirKeyboardClass +{ + GdkDeviceClass parent_class; +}; + +G_DEFINE_TYPE (GdkMirKeyboard, gdk_mir_keyboard, GDK_TYPE_DEVICE) + +GdkDevice * +_gdk_mir_keyboard_new (GdkDeviceManager *device_manager, const gchar *name) +{ + return g_object_new (GDK_TYPE_MIR_KEYBOARD, + "display", gdk_device_manager_get_display (device_manager), + "device-manager", device_manager, + "name", name, + "type", GDK_DEVICE_TYPE_MASTER, + "input-source", GDK_SOURCE_KEYBOARD, + "input-mode", GDK_MODE_SCREEN, + "has-cursor", FALSE, + NULL); +} + +static gboolean +gdk_mir_keyboard_get_history (GdkDevice *device, + GdkWindow *window, + guint32 start, + guint32 stop, + GdkTimeCoord ***events, + gint *n_events) +{ + g_printerr ("gdk_mir_keyboard_get_history\n"); + return FALSE; +} + +static void +gdk_mir_keyboard_get_state (GdkDevice *device, + GdkWindow *window, + gdouble *axes, + GdkModifierType *mask) +{ + g_printerr ("gdk_mir_keyboard_get_state\n"); +} + +static void +gdk_mir_keyboard_set_window_cursor (GdkDevice *device, + GdkWindow *window, + GdkCursor *cursor) +{ + //g_printerr ("gdk_mir_keyboard_set_window_cursor\n"); + /* Keyboards don't have cursors... */ +} + +static void +gdk_mir_keyboard_warp (GdkDevice *device, + GdkScreen *screen, + gdouble x, + gdouble y) +{ + //g_printerr ("gdk_mir_keyboard_warp\n"); + /* Can't warp a keyboard... */ +} + +static void +gdk_mir_keyboard_query_state (GdkDevice *device, + GdkWindow *window, + GdkWindow **root_window, + GdkWindow **child_window, + gdouble *root_x, + gdouble *root_y, + gdouble *win_x, + gdouble *win_y, + GdkModifierType *mask) +{ + g_printerr ("gdk_mir_keyboard_query_state\n"); +} + +static GdkGrabStatus +gdk_mir_keyboard_grab (GdkDevice *device, + GdkWindow *window, + gboolean owner_events, + GdkEventMask event_mask, + GdkWindow *confine_to, + GdkCursor *cursor, + guint32 time_) +{ + //g_printerr ("gdk_mir_keyboard_grab\n"); + /* Mir doesn't do grabs, so sure, you have the grab */ + return GDK_GRAB_SUCCESS; +} + +static void +gdk_mir_keyboard_ungrab (GdkDevice *device, + guint32 time_) +{ + //g_printerr ("gdk_mir_keyboard_ungrab\n"); + /* Mir doesn't do grabs */ +} + +static GdkWindow * +gdk_mir_keyboard_window_at_position (GdkDevice *device, + gdouble *win_x, + gdouble *win_y, + GdkModifierType *mask, + gboolean get_toplevel) +{ + //g_printerr ("gdk_mir_keyboard_window_at_position (%f, %f)\n", *win_x, *win_y); + /* Keyboard don't have locations... */ + return NULL; // FIXME: Or the window with the keyboard focus? +} + +static void +gdk_mir_keyboard_select_window_events (GdkDevice *device, + GdkWindow *window, + GdkEventMask event_mask) +{ + g_printerr ("gdk_mir_keyboard_select_window_events\n"); +} + +static void +gdk_mir_keyboard_init (GdkMirKeyboard *device) +{ +} + +static void +gdk_mir_keyboard_class_init (GdkMirKeyboardClass *klass) +{ + GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass); + + device_class->get_history = gdk_mir_keyboard_get_history; + device_class->get_state = gdk_mir_keyboard_get_state; + device_class->set_window_cursor = gdk_mir_keyboard_set_window_cursor; + device_class->warp = gdk_mir_keyboard_warp; + device_class->query_state = gdk_mir_keyboard_query_state; + device_class->grab = gdk_mir_keyboard_grab; + device_class->ungrab = gdk_mir_keyboard_ungrab; + device_class->window_at_position = gdk_mir_keyboard_window_at_position; + device_class->select_window_events = gdk_mir_keyboard_select_window_events; +} diff --git a/gdk/mir/gdkmirkeymap.c b/gdk/mir/gdkmirkeymap.c new file mode 100644 index 0000000000..3e8c829ae7 --- /dev/null +++ b/gdk/mir/gdkmirkeymap.c @@ -0,0 +1,466 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include + +#include "gdkkeysprivate.h" + +typedef struct GdkMirKeymap GdkMirKeymap; +typedef struct GdkMirKeymapClass GdkMirKeymapClass; + +#define GDK_TYPE_MIR_KEYMAP (gdk_mir_keymap_get_type ()) +#define GDK_MIR_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MIR_KEYMAP, GdkMirKeymap)) +#define GDK_MIR_KEYMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MIR_KEYMAP, GdkMirKeymapClass)) +#define GDK_IS_MIR_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_KEYMAP)) +#define GDK_IS_MIR_KEYMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MIR_KEYMAP)) +#define GDK_MIR_KEYMAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MIR_KEYMAP, GdkMirKeymapClass)) + +struct GdkMirKeymap +{ + GdkKeymap parent_instance; + + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + + PangoDirection *direction; + gboolean bidi; +}; + +struct GdkMirKeymapClass +{ + GdkKeymapClass parent_class; +}; + +G_DEFINE_TYPE (GdkMirKeymap, gdk_mir_keymap, GDK_TYPE_KEYMAP) + +GdkKeymap * +_gdk_mir_keymap_new (void) +{ + return g_object_new (GDK_TYPE_MIR_KEYMAP, NULL); +} + +static PangoDirection +gdk_mir_keymap_get_direction (GdkKeymap *keymap) +{ + //g_printerr ("gdk_mir_keymap_get_direction\n"); + GdkMirKeymap *mir_keymap = GDK_MIR_KEYMAP (keymap); + gint i; + + for (i = 0; i < xkb_keymap_num_layouts (mir_keymap->xkb_keymap); i++) + { + if (xkb_state_layout_index_is_active (mir_keymap->xkb_state, i, XKB_STATE_LAYOUT_EFFECTIVE)) + return mir_keymap->direction[i]; + } + + return PANGO_DIRECTION_NEUTRAL; +} + +static gboolean +gdk_mir_keymap_have_bidi_layouts (GdkKeymap *keymap) +{ + //g_printerr ("gdk_mir_keymap_have_bidi_layouts\n"); + return FALSE; +} + +static gboolean +gdk_mir_keymap_get_caps_lock_state (GdkKeymap *keymap) +{ + //g_printerr ("gdk_mir_keymap_get_caps_lock_state\n"); + return xkb_state_led_name_is_active (GDK_MIR_KEYMAP (keymap)->xkb_state, XKB_LED_NAME_CAPS); +} + +static gboolean +gdk_mir_keymap_get_num_lock_state (GdkKeymap *keymap) +{ + //g_printerr ("gdk_mir_keymap_get_num_lock_state\n"); + return xkb_state_led_name_is_active (GDK_MIR_KEYMAP (keymap)->xkb_state, XKB_LED_NAME_NUM); +} + +static gboolean +gdk_mir_keymap_get_entries_for_keyval (GdkKeymap *keymap, + guint keyval, + GdkKeymapKey **keys, + gint *n_keys) +{ + //g_printerr ("gdk_mir_keymap_get_entries_for_keyval\n"); + GdkMirKeymap *mir_keymap = GDK_MIR_KEYMAP (keymap); + GArray *key_array; + guint keycode; + + key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey)); + + for (keycode = 8; keycode < 255; keycode++) /* FIXME: min/max keycode */ + { + gint num_layouts, layout; + + num_layouts = xkb_keymap_num_layouts_for_key (mir_keymap->xkb_keymap, keycode); + for (layout = 0; layout < num_layouts; layout++) + { + gint num_levels, level; + + num_levels = xkb_keymap_num_levels_for_key (mir_keymap->xkb_keymap, keycode, layout); + for (level = 0; level < num_levels; level++) + { + const xkb_keysym_t *syms; + gint num_syms, sym; + + num_syms = xkb_keymap_key_get_syms_by_level (mir_keymap->xkb_keymap, keycode, layout, level, &syms); + for (sym = 0; sym < num_syms; sym++) + { + if (syms[sym] == keyval) + { + GdkKeymapKey key; + + key.keycode = keycode; + key.group = layout; + key.level = level; + + g_array_append_val (key_array, key); + } + } + } + } + } + + *n_keys = key_array->len; + *keys = (GdkKeymapKey*) g_array_free (key_array, FALSE); + + return TRUE; +} + +static gboolean +gdk_mir_keymap_get_entries_for_keycode (GdkKeymap *keymap, + guint hardware_keycode, + GdkKeymapKey **keys, + guint **keyvals, + gint *n_entries) +{ + //g_printerr ("gdk_mir_keymap_get_entries_for_keycode\n"); + GdkMirKeymap *mir_keymap = GDK_MIR_KEYMAP (keymap); + gint num_layouts, layout; + gint num_entries; + gint i; + + num_layouts = xkb_keymap_num_layouts_for_key (mir_keymap->xkb_keymap, hardware_keycode); + + num_entries = 0; + for (layout = 0; layout < num_layouts; layout++) + num_entries += xkb_keymap_num_levels_for_key (mir_keymap->xkb_keymap, hardware_keycode, layout); + + if (n_entries) + *n_entries = num_entries; + if (keys) + *keys = g_new0 (GdkKeymapKey, num_entries); + if (keyvals) + *keyvals = g_new0 (guint, num_entries); + + i = 0; + for (layout = 0; layout < num_layouts; layout++) + { + gint num_levels, level; + num_levels = xkb_keymap_num_levels_for_key (mir_keymap->xkb_keymap, hardware_keycode, layout); + for (level = 0; level < num_levels; level++) + { + const xkb_keysym_t *syms; + int num_syms; + + num_syms = xkb_keymap_key_get_syms_by_level (mir_keymap->xkb_keymap, hardware_keycode, layout, 0, &syms); + if (keys) + { + (*keys)[i].keycode = hardware_keycode; + (*keys)[i].group = layout; + (*keys)[i].level = level; + } + if (keyvals && num_syms > 0) + (*keyvals)[i] = syms[0]; + + i++; + } + } + + return num_entries > 0; +} + +static guint +gdk_mir_keymap_lookup_key (GdkKeymap *keymap, + const GdkKeymapKey *key) +{ + //g_printerr ("gdk_mir_keymap_lookup_key\n"); + GdkMirKeymap *mir_keymap = GDK_MIR_KEYMAP (keymap); + const xkb_keysym_t *syms; + int num_syms; + + num_syms = xkb_keymap_key_get_syms_by_level (mir_keymap->xkb_keymap, + key->keycode, + key->group, + key->level, + &syms); + if (num_syms > 0) + return syms[0]; + else + return XKB_KEY_NoSymbol; +} + +static guint32 +get_xkb_modifiers (struct xkb_keymap *xkb_keymap, + GdkModifierType state) +{ + guint32 mods = 0; + + if (state & GDK_SHIFT_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_SHIFT); + if (state & GDK_LOCK_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CAPS); + if (state & GDK_CONTROL_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CTRL); + if (state & GDK_MOD1_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_ALT); + if (state & GDK_MOD2_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, "Mod2"); + if (state & GDK_MOD3_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, "Mod3"); + if (state & GDK_MOD4_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_LOGO); + if (state & GDK_MOD5_MASK) + mods |= 1 << xkb_keymap_mod_get_index (xkb_keymap, "Mod5"); + + return mods; +} + +static GdkModifierType +get_gdk_modifiers (struct xkb_keymap *xkb_keymap, + guint32 mods) +{ + GdkModifierType state = 0; + + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_SHIFT))) + state |= GDK_SHIFT_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CAPS))) + state |= GDK_LOCK_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_CTRL))) + state |= GDK_CONTROL_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_ALT))) + state |= GDK_MOD1_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, "Mod2"))) + state |= GDK_MOD2_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, "Mod3"))) + state |= GDK_MOD3_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, XKB_MOD_NAME_LOGO))) + state |= GDK_MOD4_MASK; + if (mods & (1 << xkb_keymap_mod_get_index (xkb_keymap, "Mod5"))) + state |= GDK_MOD5_MASK; + + return state; +} + +static gboolean +gdk_mir_keymap_translate_keyboard_state (GdkKeymap *keymap, + guint hardware_keycode, + GdkModifierType state, + gint group, + guint *keyval, + gint *effective_group, + gint *effective_level, + GdkModifierType *consumed_modifiers) +{ + //g_printerr ("gdk_mir_keymap_translate_keyboard_state\n"); + GdkMirKeymap *mir_keymap = GDK_MIR_KEYMAP (keymap); + struct xkb_state *xkb_state; + guint32 modifiers; + guint32 consumed; + xkb_layout_index_t layout; + xkb_level_index_t level; + xkb_keysym_t sym; + + modifiers = get_xkb_modifiers (mir_keymap->xkb_keymap, state); + + xkb_state = xkb_state_new (mir_keymap->xkb_keymap); + + xkb_state_update_mask (xkb_state, modifiers, 0, 0, group, 0, 0); + + layout = xkb_state_key_get_layout (xkb_state, hardware_keycode); + level = xkb_state_key_get_level (xkb_state, hardware_keycode, layout); + sym = xkb_state_key_get_one_sym (xkb_state, hardware_keycode); + consumed = modifiers & ~xkb_state_mod_mask_remove_consumed (xkb_state, hardware_keycode, modifiers); + + xkb_state_unref (xkb_state); + + if (keyval) + *keyval = sym; + if (effective_group) + *effective_group = layout; + if (effective_level) + *effective_level = level; + if (consumed_modifiers) + *consumed_modifiers = get_gdk_modifiers (mir_keymap->xkb_keymap, consumed); + + return TRUE; +} + +static void +gdk_mir_keymap_add_virtual_modifiers (GdkKeymap *keymap, + GdkModifierType *state) +{ + //g_printerr ("gdk_mir_keymap_add_virtual_modifiers\n"); + // FIXME: What is this? +} + +static gboolean +gdk_mir_keymap_map_virtual_modifiers (GdkKeymap *keymap, + GdkModifierType *state) +{ + //g_printerr ("gdk_mir_keymap_map_virtual_modifiers\n"); + // FIXME: What is this? + return TRUE; +} + +static guint +gdk_mir_keymap_get_modifier_state (GdkKeymap *keymap) +{ + //g_printerr ("gdk_mir_keymap_get_modifier_state\n"); + GdkMirKeymap *mir_keymap = GDK_MIR_KEYMAP (keymap); + xkb_mod_mask_t mods; + + mods = xkb_state_serialize_mods (mir_keymap->xkb_state, XKB_STATE_MODS_EFFECTIVE); + + return get_gdk_modifiers (mir_keymap->xkb_keymap, mods); +} + +static void +update_direction (GdkMirKeymap *keymap) +{ + gint num_layouts; + gint *rtl; + guint key; + gboolean have_rtl, have_ltr; + gint i; + + num_layouts = xkb_keymap_num_layouts (keymap->xkb_keymap); + + g_free (keymap->direction); + keymap->direction = g_new0 (PangoDirection, num_layouts); + + rtl = g_new0 (gint, num_layouts); + + for (key = 8; key < 255; key++) /* FIXME: min/max keycode */ + { + gint layouts; + gint layout; + + layouts = xkb_keymap_num_layouts_for_key (keymap->xkb_keymap, key); + for (layout = 0; layout < layouts; layout++) + { + const xkb_keysym_t *syms; + gint num_syms; + gint sym; + + num_syms = xkb_keymap_key_get_syms_by_level (keymap->xkb_keymap, key, layout, 0, &syms); + for (sym = 0; sym < num_syms; sym++) + { + PangoDirection dir; + dir = pango_unichar_direction (xkb_keysym_to_utf32 (syms[sym])); + switch (dir) + { + case PANGO_DIRECTION_RTL: + rtl[layout]++; + break; + case PANGO_DIRECTION_LTR: + rtl[layout]--; + break; + default: + break; + } + } + } + } + + have_rtl = have_ltr = FALSE; + for (i = 0; i < num_layouts; i++) + { + if (rtl[i] > 0) + { + keymap->direction[i] = PANGO_DIRECTION_RTL; + have_rtl = TRUE; + } + else + { + keymap->direction[i] = PANGO_DIRECTION_LTR; + have_ltr = TRUE; + } + } + + if (have_rtl && have_ltr) + keymap->bidi = TRUE; + + g_free (rtl); +} + +static void +gdk_mir_keymap_init (GdkMirKeymap *keymap) +{ + struct xkb_context *context; + struct xkb_rule_names names; + + context = xkb_context_new (0); + + names.rules = "evdev"; + names.model = "pc105"; + names.layout = "us"; + names.variant = ""; + names.options = ""; + keymap->xkb_keymap = xkb_keymap_new_from_names (context, &names, 0); + keymap->xkb_state = xkb_state_new (keymap->xkb_keymap); + + xkb_context_unref (context); + + update_direction (keymap); +} + +static void +gdk_mir_keymap_finalize (GObject *object) +{ + GdkMirKeymap *keymap = GDK_MIR_KEYMAP (object); + + xkb_keymap_unref (keymap->xkb_keymap); + xkb_state_unref (keymap->xkb_state); + g_free (keymap->direction); + + G_OBJECT_CLASS (gdk_mir_keymap_parent_class)->finalize (object); +} + +static void +gdk_mir_keymap_class_init (GdkMirKeymapClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass); + + object_class->finalize = gdk_mir_keymap_finalize; + + keymap_class->get_direction = gdk_mir_keymap_get_direction; + keymap_class->have_bidi_layouts = gdk_mir_keymap_have_bidi_layouts; + keymap_class->get_caps_lock_state = gdk_mir_keymap_get_caps_lock_state; + keymap_class->get_num_lock_state = gdk_mir_keymap_get_num_lock_state; + keymap_class->get_entries_for_keyval = gdk_mir_keymap_get_entries_for_keyval; + keymap_class->get_entries_for_keycode = gdk_mir_keymap_get_entries_for_keycode; + keymap_class->lookup_key = gdk_mir_keymap_lookup_key; + keymap_class->translate_keyboard_state = gdk_mir_keymap_translate_keyboard_state; + keymap_class->add_virtual_modifiers = gdk_mir_keymap_add_virtual_modifiers; + keymap_class->map_virtual_modifiers = gdk_mir_keymap_map_virtual_modifiers; + keymap_class->get_modifier_state = gdk_mir_keymap_get_modifier_state; +} diff --git a/gdk/mir/gdkmirpointer.c b/gdk/mir/gdkmirpointer.c new file mode 100644 index 0000000000..96c7e743fd --- /dev/null +++ b/gdk/mir/gdkmirpointer.c @@ -0,0 +1,250 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkdeviceprivate.h" +#include "gdkscreen.h" +#include "gdkwindow.h" + +typedef struct GdkMirPointer GdkMirPointer; +typedef struct GdkMirPointerClass GdkMirPointerClass; + +#define GDK_TYPE_MIR_POINTER (gdk_mir_pointer_get_type ()) +#define GDK_MIR_POINTER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MIR_POINTER, GdkMirPointer)) +#define GDK_MIR_POINTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MIR_POINTER, GdkMirPointerClass)) +#define GDK_IS_MIR_POINTER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_POINTER)) +#define GDK_IS_MIR_POINTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MIR_POINTER)) +#define GDK_MIR_POINTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MIR_POINTER, GdkMirPointerClass)) + +struct GdkMirPointer +{ + GdkDevice parent_instance; + + /* Location of pointer */ + gdouble x; + gdouble y; + + /* Window this pointer is over */ + GdkWindow *over_window; + + /* Current modifier mask */ + GdkModifierType modifier_mask; +}; + +struct GdkMirPointerClass +{ + GdkDeviceClass parent_class; +}; + +G_DEFINE_TYPE (GdkMirPointer, gdk_mir_pointer, GDK_TYPE_DEVICE) + +GdkDevice * +_gdk_mir_pointer_new (GdkDeviceManager *device_manager, const gchar *name) +{ + return g_object_new (GDK_TYPE_MIR_POINTER, + "display", gdk_device_manager_get_display (device_manager), + "device-manager", device_manager, + "name", name, + "type", GDK_DEVICE_TYPE_MASTER, + "input-source", GDK_SOURCE_MOUSE, + "input-mode", GDK_MODE_SCREEN, + "has-cursor", TRUE, + NULL); +} + +void +_gdk_mir_pointer_set_location (GdkDevice *pointer, + gdouble x, + gdouble y, + GdkWindow *window, + GdkModifierType mask) +{ + GdkMirPointer *p = GDK_MIR_POINTER (pointer); + + p->x = x; + p->y = y; + if (p->over_window) + g_object_unref (p->over_window); + p->over_window = g_object_ref (window); + p->modifier_mask = mask; +} + +static gboolean +gdk_mir_pointer_get_history (GdkDevice *device, + GdkWindow *window, + guint32 start, + guint32 stop, + GdkTimeCoord ***events, + gint *n_events) +{ + g_printerr ("gdk_mir_pointer_get_history\n"); + return FALSE; +} + +static void +gdk_mir_pointer_get_state (GdkDevice *device, + GdkWindow *window, + gdouble *axes, + GdkModifierType *mask) +{ + //g_printerr ("gdk_mir_pointer_get_state\n"); + GdkMirPointer *p = GDK_MIR_POINTER (device); + gdouble x, y; + + gdk_window_get_device_position_double (window, device, &x, &y, mask); + if (axes) + { + axes[0] = p->x; + axes[1] = p->y; + } +} + +static void +gdk_mir_pointer_set_window_cursor (GdkDevice *device, + GdkWindow *window, + GdkCursor *cursor) +{ + //g_printerr ("gdk_mir_pointer_set_window_cursor\n"); + /* Mir doesn't support cursors */ +} + +static void +gdk_mir_pointer_warp (GdkDevice *device, + GdkScreen *screen, + gdouble x, + gdouble y) +{ + //g_printerr ("gdk_mir_pointer_warp\n"); + /* Mir doesn't support warping */ +} + +static void +gdk_mir_pointer_query_state (GdkDevice *device, + GdkWindow *window, + GdkWindow **root_window, + GdkWindow **child_window, + gdouble *root_x, + gdouble *root_y, + gdouble *win_x, + gdouble *win_y, + GdkModifierType *mask) +{ + //g_printerr ("gdk_mir_pointer_query_state\n"); + GdkMirPointer *p = GDK_MIR_POINTER (device); + + if (root_window) + *root_window = gdk_screen_get_root_window (gdk_display_get_default_screen (gdk_device_get_display (device))); + if (child_window) + *child_window = p->over_window; + if (root_x) + *root_x = p->x; + if (root_y) + *root_y = p->y; + if (win_x) + *win_x = p->x; // FIXME + if (win_y) + *win_y = p->y; + if (mask) + *mask = p->modifier_mask; +} + +static GdkGrabStatus +gdk_mir_pointer_grab (GdkDevice *device, + GdkWindow *window, + gboolean owner_events, + GdkEventMask event_mask, + GdkWindow *confine_to, + GdkCursor *cursor, + guint32 time_) +{ + //g_printerr ("gdk_mir_pointer_grab\n"); + /* Mir doesn't do grabs, so sure, you have the grab */ + return GDK_GRAB_SUCCESS; +} + +static void +gdk_mir_pointer_ungrab (GdkDevice *device, + guint32 time_) +{ + //g_printerr ("gdk_mir_pointer_ungrab\n"); + /* Mir doesn't do grabs */ +} + +static GdkWindow * +gdk_mir_pointer_window_at_position (GdkDevice *device, + gdouble *win_x, + gdouble *win_y, + GdkModifierType *mask, + gboolean get_toplevel) +{ + //g_printerr ("gdk_mir_pointer_window_at_position\n"); + GdkMirPointer *p = GDK_MIR_POINTER (device); + + if (win_x) + *win_x = p->x; + if (win_y) + *win_y = p->y; + if (mask) + *mask = p->modifier_mask; + + return p->over_window; +} + +static void +gdk_mir_pointer_select_window_events (GdkDevice *device, + GdkWindow *window, + GdkEventMask event_mask) +{ + g_printerr ("gdk_mir_pointer_select_window_events\n"); + // FIXME? +} + +static void +gdk_mir_pointer_init (GdkMirPointer *device) +{ +} + +static void +gdk_mir_pointer_finalize (GObject *object) +{ + GdkMirPointer *p = GDK_MIR_POINTER (object); + + if (p->over_window) + g_object_unref (p->over_window); + + G_OBJECT_CLASS (gdk_mir_pointer_parent_class)->finalize (object); +} + +static void +gdk_mir_pointer_class_init (GdkMirPointerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass); + + object_class->finalize = gdk_mir_pointer_finalize; + + device_class->get_history = gdk_mir_pointer_get_history; + device_class->get_state = gdk_mir_pointer_get_state; + device_class->set_window_cursor = gdk_mir_pointer_set_window_cursor; + device_class->warp = gdk_mir_pointer_warp; + device_class->query_state = gdk_mir_pointer_query_state; + device_class->grab = gdk_mir_pointer_grab; + device_class->ungrab = gdk_mir_pointer_ungrab; + device_class->window_at_position = gdk_mir_pointer_window_at_position; + device_class->select_window_events = gdk_mir_pointer_select_window_events; +} diff --git a/gdk/mir/gdkmirscreen.c b/gdk/mir/gdkmirscreen.c new file mode 100644 index 0000000000..befc84c823 --- /dev/null +++ b/gdk/mir/gdkmirscreen.c @@ -0,0 +1,720 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include + +#include "gdkscreenprivate.h" +#include "gdkdisplayprivate.h" +#include "gdkvisualprivate.h" +#include "gdkinternals.h" + +#include "gdkmir.h" +#include "gdkmir-private.h" + +#define VISUAL_TYPE GDK_VISUAL_TRUE_COLOR +#define VISUAL_DEPTH 32 + +typedef struct GdkMirScreen GdkMirScreen; +typedef struct GdkMirScreenClass GdkMirScreenClass; + +#define GDK_TYPE_MIR_SCREEN (gdk_mir_screen_get_type ()) +#define GDK_MIR_SCREEN(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MIR_SCREEN, GdkMirScreen)) +#define GDK_MIR_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MIR_SCREEN, GdkMirScreenClass)) +#define GDK_IS_MIR_SCREEN(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MIR_SCREEN)) +#define GDK_IS_MIR_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MIR_SCREEN)) +#define GDK_MIR_SCREEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MIR_SCREEN, GdkMirScreenClass)) + +struct GdkMirScreen +{ + GdkScreen parent_instance; + + /* Display this screen is running on */ + GdkDisplay *display; + + /* Current monitor configuration */ + MirDisplayConfiguration *display_config; + + GdkVisual *visual; + + GdkWindow *root_window; +}; + +struct GdkMirScreenClass +{ + GdkScreenClass parent_class; +}; + +G_DEFINE_TYPE (GdkMirScreen, gdk_mir_screen, GDK_TYPE_SCREEN) + +static MirConnection * +get_connection (GdkMirScreen *screen) +{ + return gdk_mir_display_get_mir_connection (GDK_DISPLAY (screen->display)); +} + +static void +get_screen_size (MirDisplayConfiguration *config, gint *width, gint *height) +{ + uint32_t i; + + *width = 0; + *height = 0; + + if (!config) + return; + + for (i = 0; i < config->num_outputs; i++) + { + MirDisplayOutput *o = &config->outputs[i]; + gint w, h; + + if (!o->used) + continue; + + w = o->position_x + o->modes[o->current_mode].horizontal_resolution; + if (w > *width) + *width = w; + h = o->position_y + o->modes[o->current_mode].vertical_resolution; + if (h > *height) + *height = h; + } +} + +static void +update_display_config (GdkMirScreen *screen) +{ + gdk_mir_display_get_mir_connection (GDK_DISPLAY (screen->display)); + mir_display_config_destroy (screen->display_config); + screen->display_config = mir_connection_create_display_config (get_connection (screen)); +} + +static void +config_changed_cb (MirConnection *connection, void *data) +{ + GdkMirScreen *screen = data; + gint old_width, old_height, new_width, new_height; + + get_screen_size (screen->display_config, &old_width, &old_height); + update_display_config (screen); + get_screen_size (screen->display_config, &new_width, &new_height); + + g_signal_emit_by_name (screen, "monitors-changed"); + if (old_width > 0 && (old_width != new_width || old_height != new_height)) + g_signal_emit_by_name (screen, "size-changed"); +} + +GdkScreen * +_gdk_mir_screen_new (GdkDisplay *display) +{ + GdkMirScreen *screen; + + screen = g_object_new (GDK_TYPE_MIR_SCREEN, NULL); + screen->display = display; + mir_connection_set_display_config_change_callback (get_connection (screen), config_changed_cb, display); + update_display_config (screen); + + return GDK_SCREEN (screen); +} + +static void +gdk_mir_screen_dispose (GObject *object) +{ + G_OBJECT_CLASS (gdk_mir_screen_parent_class)->dispose (object); +} + +static void +gdk_mir_screen_finalize (GObject *object) +{ + G_OBJECT_CLASS (gdk_mir_screen_parent_class)->finalize (object); +} + +static GdkDisplay * +gdk_mir_screen_get_display (GdkScreen *screen) +{ + //g_printerr ("gdk_mir_screen_get_display\n"); + return GDK_DISPLAY (GDK_MIR_SCREEN (screen)->display); +} + +static MirDisplayOutput * +get_output (GdkScreen *screen, gint monitor_num) +{ + MirDisplayConfiguration *config; + uint32_t i, j; + + config = GDK_MIR_SCREEN (screen)->display_config; + + for (i = 0, j = 0; i < config->num_outputs; i++) + { + if (!config->outputs[i].used) + continue; + + if (j == monitor_num) + return &config->outputs[i]; + j++; + } + + return NULL; +} + +static gint +gdk_mir_screen_get_width (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_get_width\n"); + gint width, height; + get_screen_size (GDK_MIR_SCREEN (screen)->display_config, &width, &height); + return width; +} + +static gint +gdk_mir_screen_get_height (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_get_height\n"); + gint width, height; + get_screen_size (GDK_MIR_SCREEN (screen)->display_config, &width, &height); + return height; +} + +static gint +gdk_mir_screen_get_width_mm (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_get_width_mm\n"); + // FIXME: A combination of all screens? + return get_output (screen, 0)->physical_width_mm; +} + +static gint +gdk_mir_screen_get_height_mm (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_get_height_mm\n"); + // FIXME: A combination of all screens? + return get_output (screen, 0)->physical_height_mm; +} + +static gint +gdk_mir_screen_get_number (GdkScreen *screen) +{ + //g_printerr ("gdk_mir_screen_get_number\n"); + /* There is only one screen... */ + return 0; +} + +static GdkWindow * +gdk_mir_screen_get_root_window (GdkScreen *screen) +{ + //g_printerr ("gdk_mir_screen_get_root_window\n"); + GdkMirScreen *s = GDK_MIR_SCREEN (screen); + gint width, height; + + if (s->root_window) + return s->root_window; + + get_screen_size (GDK_MIR_SCREEN (screen)->display_config, &width, &height); + + s->root_window = _gdk_display_create_window (s->display); + s->root_window->impl = _gdk_mir_window_impl_new (); + s->root_window->impl_window = s->root_window; + s->root_window->visual = s->visual; + s->root_window->window_type = GDK_WINDOW_ROOT; + s->root_window->depth = VISUAL_DEPTH; + s->root_window->x = 0; + s->root_window->y = 0; + s->root_window->abs_x = 0; + s->root_window->abs_y = 0; + s->root_window->width = width; + s->root_window->height = height; + s->root_window->viewable = TRUE; + + return s->root_window; +} + +static gint +gdk_mir_screen_get_n_monitors (GdkScreen *screen) +{ + //g_printerr ("gdk_mir_screen_get_n_monitors\n"); + MirDisplayConfiguration *config; + uint32_t i; + gint count = 0; + + config = GDK_MIR_SCREEN (screen)->display_config; + + for (i = 0; i < config->num_outputs; i++) + if (config->outputs[i].used) + count++; + + return count; +} + +static gint +gdk_mir_screen_get_primary_monitor (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_get_primary_monitor\n"); + return 0; //? +} + +static gint +gdk_mir_screen_get_monitor_width_mm (GdkScreen *screen, + gint monitor_num) +{ + g_printerr ("gdk_mir_screen_get_monitor_width_mm (%d)\n", monitor_num); + return get_output (screen, monitor_num)->physical_width_mm; +} + +static gint +gdk_mir_screen_get_monitor_height_mm (GdkScreen *screen, + gint monitor_num) +{ + g_printerr ("gdk_mir_screen_get_monitor_height_mm (%d)\n", monitor_num); + return get_output (screen, monitor_num)->physical_height_mm; +} + +static gchar * +gdk_mir_screen_get_monitor_plug_name (GdkScreen *screen, + gint monitor_num) +{ + g_printerr ("gdk_mir_screen_get_monitor_plug_name (%d)\n", monitor_num); + return NULL; //? +} + +static void +gdk_mir_screen_get_monitor_geometry (GdkScreen *screen, + gint monitor_num, + GdkRectangle *dest) +{ + //g_printerr ("gdk_mir_screen_get_monitor_geometry (%d)\n", monitor_num); + MirDisplayOutput *output; + MirDisplayMode *mode; + + output = get_output (screen, monitor_num); + mode = &output->modes[output->current_mode]; + dest->x = output->position_x; + dest->y = output->position_y; + dest->width = mode->horizontal_resolution; + dest->height = mode->vertical_resolution; +} + +static void +gdk_mir_screen_get_monitor_workarea (GdkScreen *screen, + gint monitor_num, + GdkRectangle *dest) +{ + //g_printerr ("gdk_mir_screen_get_monitor_workarea (%d)\n", monitor_num); + // FIXME: Don't know what this is + gdk_mir_screen_get_monitor_geometry (screen, monitor_num, dest); +} + +static GList * +gdk_mir_screen_list_visuals (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_list_visuals\n"); + return g_list_append (NULL, GDK_MIR_SCREEN (screen)->visual); +} + +static GdkVisual * +gdk_mir_screen_get_system_visual (GdkScreen *screen) +{ + //g_printerr ("gdk_mir_screen_get_system_visual\n"); + return GDK_MIR_SCREEN (screen)->visual; +} + +static GdkVisual * +gdk_mir_screen_get_rgba_visual (GdkScreen *screen) +{ + //g_printerr ("gdk_mir_screen_get_rgba_visual\n"); + return GDK_MIR_SCREEN (screen)->visual; +} + +static gboolean +gdk_mir_screen_is_composited (GdkScreen *screen) +{ + //g_printerr ("gdk_mir_screen_is_composited\n"); + /* We're always composited */ + return TRUE; +} + +static gchar * +gdk_mir_screen_make_display_name (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_make_display_name\n"); + return NULL; // FIXME +} + +static GdkWindow * +gdk_mir_screen_get_active_window (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_get_active_window\n"); + return NULL; // FIXME +} + +static GList * +gdk_mir_screen_get_window_stack (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_get_window_stack\n"); + return NULL; // FIXME +} + +static void +gdk_mir_screen_broadcast_client_message (GdkScreen *screen, + GdkEvent *event) +{ + g_printerr ("gdk_mir_screen_broadcast_client_message\n"); + // FIXME +} + +static gboolean +gdk_mir_screen_get_setting (GdkScreen *screen, + const gchar *name, + GValue *value) +{ + //g_printerr ("gdk_mir_screen_get_setting (\"%s\")\n", name); + + if (strcmp (name, "gtk-theme-name") == 0) + { + g_value_set_string (value, "Ambiance"); + return TRUE; + } + + if (strcmp (name, "gtk-font-name") == 0) + { + g_value_set_string (value, "Ubuntu"); + return TRUE; + } + + if (strcmp (name, "gtk-enable-animations") == 0) + { + g_value_set_boolean (value, TRUE); + return TRUE; + } + + if (strcmp (name, "gtk-xft-dpi") == 0) + { + g_value_set_int (value, 96 * 1024); + return TRUE; + } + + if (strcmp (name, "gtk-xft-antialias") == 0) + { + g_value_set_int (value, TRUE); + return TRUE; + } + + if (strcmp (name, "gtk-xft-hinting") == 0) + { + g_value_set_int (value, TRUE); + return TRUE; + } + + if (strcmp (name, "gtk-xft-hintstyle") == 0) + { + g_value_set_static_string (value, "hintfull"); + return TRUE; + } + + if (strcmp (name, "gtk-xft-rgba") == 0) + { + g_value_set_static_string (value, "rgba"); + return TRUE; + } + + if (g_str_equal (name, "gtk-modules")) + { + g_value_set_string (value, NULL); + return TRUE; + } + + if (g_str_equal (name, "gtk-application-prefer-dark-theme")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + if (g_str_equal (name, "gtk-key-theme-name")) + { + g_value_set_string (value, NULL); + return TRUE; + } + + if (g_str_equal (name, "gtk-double-click-time")) + { + g_value_set_int (value, 250); + return TRUE; + } + + if (g_str_equal (name, "gtk-double-click-distance")) + { + g_value_set_int (value, 5); + return TRUE; + } + + if (g_str_equal (name, "gtk-cursor-theme-name")) + { + g_value_set_string (value, "Raleigh"); + return TRUE; + } + + if (g_str_equal (name, "gtk-cursor-theme-size")) + { + g_value_set_int (value, 128); + return TRUE; + } + + if (g_str_equal (name, "gtk-icon-theme-name")) + { + g_value_set_string (value, "hicolor"); + return TRUE; + } + + if (g_str_equal (name, "gtk-shell-shows-app-menu")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + if (g_str_equal (name, "gtk-shell-shows-menubar")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + if (g_str_equal (name, "gtk-shell-shows-desktop")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + if (g_str_equal (name, "gtk-recent-files-enabled")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + if (g_str_equal (name, "gtk-alternative-sort-arrows")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + if (g_str_equal (name, "gtk-enable-accels")) + { + g_value_set_boolean (value, TRUE); + return TRUE; + } + + if (g_str_equal (name, "gtk-enable-mnemonics")) + { + g_value_set_boolean (value, TRUE); + return TRUE; + } + + if (g_str_equal (name, "gtk-menu-images")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + if (g_str_equal (name, "gtk-button-images")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + if (g_str_equal (name, "gtk-split-cursor")) + { + g_value_set_boolean (value, TRUE); + return TRUE; + } + + if (g_str_equal (name, "gtk-im-module")) + { + g_value_set_string (value, NULL); + return TRUE; + } + + if (g_str_equal (name, "gtk-menu-bar-accel")) + { + g_value_set_string (value, "F10"); + return TRUE; + } + + if (g_str_equal (name, "gtk-cursor-blink")) + { + g_value_set_boolean (value, TRUE); + return TRUE; + } + + if (g_str_equal (name, "gtk-cursor-blink-time")) + { + g_value_set_int (value, 1200); + return TRUE; + } + + if (g_str_equal (name, "gtk-cursor-blink-timeout")) + { + g_value_set_int (value, 10); + return TRUE; + } + + if (g_str_equal (name, "gtk-entry-select-on-focus")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + if (g_str_equal (name, "gtk-error-bell")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + if (g_str_equal (name, "gtk-label-select-on-focus")) + { + g_value_set_boolean (value, FALSE); + return TRUE; + } + + g_warning ("unknown property %s", name); + + return FALSE; +} + +static gint +gdk_mir_screen_visual_get_best_depth (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_visual_get_best_depth\n"); + return VISUAL_DEPTH; +} + +static GdkVisualType +gdk_mir_screen_visual_get_best_type (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_visual_get_best_type\n"); + return VISUAL_TYPE; +} + +static GdkVisual* +gdk_mir_screen_visual_get_best (GdkScreen *screen) +{ + g_printerr ("gdk_mir_screen_visual_get_best\n"); + return GDK_MIR_SCREEN (screen)->visual; +} + +static GdkVisual* +gdk_mir_screen_visual_get_best_with_depth (GdkScreen *screen, + gint depth) +{ + g_printerr ("gdk_mir_screen_visual_get_best_with_depth (%d)\n", depth); + return GDK_MIR_SCREEN (screen)->visual; +} + +static GdkVisual* +gdk_mir_screen_visual_get_best_with_type (GdkScreen *screen, + GdkVisualType visual_type) +{ + g_printerr ("gdk_mir_screen_visual_get_best_with_type (%d)\n", visual_type); + return GDK_MIR_SCREEN (screen)->visual; +} + +static GdkVisual* +gdk_mir_screen_visual_get_best_with_both (GdkScreen *screen, + gint depth, + GdkVisualType visual_type) +{ + g_printerr ("gdk_mir_screen_visual_get_best_with_both\n"); + return GDK_MIR_SCREEN (screen)->visual; +} + +static void +gdk_mir_screen_query_depths (GdkScreen *screen, + gint **depths, + gint *count) +{ + g_printerr ("gdk_mir_screen_query_depths\n"); + static gint supported_depths[] = { VISUAL_DEPTH }; + *depths = supported_depths; + *count = 1; +} + +static void +gdk_mir_screen_query_visual_types (GdkScreen *screen, + GdkVisualType **visual_types, + gint *count) +{ + g_printerr ("gdk_mir_screen_query_visual_types\n"); + static GdkVisualType supported_visual_types[] = { VISUAL_TYPE }; + *visual_types = supported_visual_types; + *count = 1; +} + +static gint +gdk_mir_screen_get_monitor_scale_factor (GdkScreen *screen, + gint monitor_num) +{ + //g_printerr ("gdk_mir_screen_get_monitor_scale_factor (%d)\n", monitor_num); + /* Don't support monitor scaling */ + return 1; +} + +static void +gdk_mir_screen_init (GdkMirScreen *screen) +{ + screen->visual = g_object_new (GDK_TYPE_VISUAL, NULL); + screen->visual->screen = GDK_SCREEN (screen); + screen->visual->type = VISUAL_TYPE; + screen->visual->depth = VISUAL_DEPTH; +} + +static void +gdk_mir_screen_class_init (GdkMirScreenClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkScreenClass *screen_class = GDK_SCREEN_CLASS (klass); + + object_class->dispose = gdk_mir_screen_dispose; + object_class->finalize = gdk_mir_screen_finalize; + + screen_class->get_display = gdk_mir_screen_get_display; + screen_class->get_width = gdk_mir_screen_get_width; + screen_class->get_height = gdk_mir_screen_get_height; + screen_class->get_width_mm = gdk_mir_screen_get_width_mm; + screen_class->get_height_mm = gdk_mir_screen_get_height_mm; + screen_class->get_number = gdk_mir_screen_get_number; + screen_class->get_root_window = gdk_mir_screen_get_root_window; + screen_class->get_n_monitors = gdk_mir_screen_get_n_monitors; + screen_class->get_primary_monitor = gdk_mir_screen_get_primary_monitor; + screen_class->get_monitor_width_mm = gdk_mir_screen_get_monitor_width_mm; + screen_class->get_monitor_height_mm = gdk_mir_screen_get_monitor_height_mm; + screen_class->get_monitor_plug_name = gdk_mir_screen_get_monitor_plug_name; + screen_class->get_monitor_geometry = gdk_mir_screen_get_monitor_geometry; + screen_class->get_monitor_workarea = gdk_mir_screen_get_monitor_workarea; + screen_class->list_visuals = gdk_mir_screen_list_visuals; + screen_class->get_system_visual = gdk_mir_screen_get_system_visual; + screen_class->get_rgba_visual = gdk_mir_screen_get_rgba_visual; + screen_class->is_composited = gdk_mir_screen_is_composited; + screen_class->make_display_name = gdk_mir_screen_make_display_name; + screen_class->get_active_window = gdk_mir_screen_get_active_window; + screen_class->get_window_stack = gdk_mir_screen_get_window_stack; + screen_class->broadcast_client_message = gdk_mir_screen_broadcast_client_message; + screen_class->get_setting = gdk_mir_screen_get_setting; + screen_class->visual_get_best_depth = gdk_mir_screen_visual_get_best_depth; + screen_class->visual_get_best_type = gdk_mir_screen_visual_get_best_type; + screen_class->visual_get_best = gdk_mir_screen_visual_get_best; + screen_class->visual_get_best_with_depth = gdk_mir_screen_visual_get_best_with_depth; + screen_class->visual_get_best_with_type = gdk_mir_screen_visual_get_best_with_type; + screen_class->visual_get_best_with_both = gdk_mir_screen_visual_get_best_with_both; + screen_class->query_depths = gdk_mir_screen_query_depths; + screen_class->query_visual_types = gdk_mir_screen_query_visual_types; + screen_class->get_monitor_scale_factor = gdk_mir_screen_get_monitor_scale_factor; +} diff --git a/gdk/mir/gdkmirwindow.c b/gdk/mir/gdkmirwindow.c new file mode 100644 index 0000000000..03da7e0013 --- /dev/null +++ b/gdk/mir/gdkmirwindow.c @@ -0,0 +1,52 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gdkinternals.h" + +#include "gdkmir.h" + +#define GDK_MIR_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WINDOW_MIR, GdkMirWindow)) +#define GDK_MIR_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW_MIR, GdkMirWindowClass)) +#define GDK_IS_WINDOW_MIR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WINDOW_MIR)) +#define GDK_MIR_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW_MIR, GdkMirWindowClass)) + +typedef struct _GdkMirWindow GdkMirWindow; +typedef struct _GdkMirWindowClass GdkMirWindowClass; + +struct _GdkMirWindow +{ + GdkWindow parent_instance; +}; + +struct _GdkMirWindowClass +{ + GdkWindowClass parent_class; +}; + +G_DEFINE_TYPE (GdkMirWindow, gdk_mir_window, GDK_TYPE_WINDOW) + +static void +gdk_mir_window_init (GdkMirWindow *impl) +{ +} + +static void +gdk_mir_window_class_init (GdkMirWindowClass *klass) +{ +} diff --git a/gdk/mir/gdkmirwindowimpl.c b/gdk/mir/gdkmirwindowimpl.c new file mode 100644 index 0000000000..2be0ca406b --- /dev/null +++ b/gdk/mir/gdkmirwindowimpl.c @@ -0,0 +1,1239 @@ +/* + * Copyright © 2014 Canonical Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include + +#include "config.h" + +#include "gdk.h" +#include "gdkmir.h" +#include "gdkmir-private.h" + +#include "gdkwindowimpl.h" +#include "gdkinternals.h" +#include "gdkdisplayprivate.h" +#include "gdkdeviceprivate.h" + +#define GDK_MIR_WINDOW_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW_IMPL_MIR, GdkMirWindowImplClass)) +#define GDK_IS_WINDOW_IMPL_MIR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WINDOW_IMPL_MIR)) +#define GDK_MIR_WINDOW_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW_IMPL_MIR, GdkMirWindowImplClass)) + +typedef struct _GdkMirWindowImplClass GdkMirWindowImplClass; + +struct _GdkMirWindowImpl +{ + GdkWindowImpl parent_instance; + + /* Window we are temporary for */ + GdkWindow *transient_for; + gint transient_x; + gint transient_y; + + /* Child windows (e.g. tooltips) */ + GList *transient_children; + + /* Desired surface attributes */ + MirSurfaceType surface_type; // FIXME + MirSurfaceState surface_state; + + /* Pattern for background */ + cairo_pattern_t *background; + + /* Current button state for checking which buttons are being pressed / released */ + gdouble x; + gdouble y; + MirMotionButton button_state; + + /* Surface being rendered to (only exists when window visible) */ + MirSurface *surface; + + /* Cairo context for current frame */ + cairo_surface_t *cairo_surface; + + /* TRUE if the window can be seen */ + gboolean visible; + + /* TRUE if cursor is inside this window */ + gboolean cursor_inside; +}; + +struct _GdkMirWindowImplClass +{ + GdkWindowImplClass parent_class; +}; + +G_DEFINE_TYPE (GdkMirWindowImpl, gdk_mir_window_impl, GDK_TYPE_WINDOW_IMPL) + +static cairo_surface_t *gdk_mir_window_impl_ref_cairo_surface (GdkWindow *window); + +GdkWindowImpl * +_gdk_mir_window_impl_new (void) +{ + return g_object_new (GDK_TYPE_MIR_WINDOW_IMPL, NULL); +} + +void +_gdk_mir_window_impl_set_surface_state (GdkMirWindowImpl *impl, MirSurfaceState state) +{ + impl->surface_state = state; +} + +void +_gdk_mir_window_impl_set_cursor_state (GdkMirWindowImpl *impl, + gdouble x, + gdouble y, + gboolean cursor_inside, + MirMotionButton button_state) +{ + impl->x = x; + impl->y = y; + impl->cursor_inside = cursor_inside; + impl->button_state = button_state; +} + +void +_gdk_mir_window_impl_get_cursor_state (GdkMirWindowImpl *impl, + gdouble *x, + gdouble *y, + gboolean *cursor_inside, + MirMotionButton *button_state) +{ + if (x) + *x = impl->x; + if (y) + *y = impl->y; + if (cursor_inside) + *cursor_inside = impl->cursor_inside; + if (button_state) + *button_state = impl->button_state; +} + +static void +gdk_mir_window_impl_init (GdkMirWindowImpl *impl) +{ +} + +static MirConnection * +get_connection (GdkWindow *window) +{ + return gdk_mir_display_get_mir_connection (gdk_window_get_display (window)); +} + +static void +set_surface_state (GdkMirWindowImpl *impl, + MirSurfaceState state) +{ + impl->surface_state = state; + if (impl->surface) + mir_surface_set_state (impl->surface, state); +} + +static void +event_cb (MirSurface *surface, + const MirEvent *event, + void *context) +{ + _gdk_mir_event_source_queue (context, event); +} + +static void +ensure_surface (GdkWindow *window) +{ + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + MirPixelFormat formats[100], pixel_format = mir_pixel_format_invalid; + unsigned int n_formats, i; + MirSurfaceParameters parameters; + MirEventDelegate event_delegate = { event_cb, NULL }; + GdkMirWindowReference *window_ref; + + if (impl->surface) + return; + + /* no destroy notify -- we must leak for now + * https://bugs.launchpad.net/mir/+bug/1324100 + */ + window_ref = _gdk_mir_event_source_get_window_reference (window); + + event_delegate.context = window_ref; + + // Should probably calculate this once? + // Should prefer certain formats over others + mir_connection_get_available_surface_formats (get_connection (window), formats, 100, &n_formats); + for (i = 0; i < n_formats; i++) + if (formats[i] == mir_pixel_format_argb_8888) + { + pixel_format = formats[i]; + break; + } + + parameters.name = "GTK+ Mir"; + parameters.width = window->width; + parameters.height = window->height; + parameters.pixel_format = pixel_format; + parameters.buffer_usage = mir_buffer_usage_software; + parameters.output_id = mir_display_output_id_invalid; + impl->surface = mir_connection_create_surface_sync (get_connection (window), ¶meters); + + MirGraphicsRegion region; + MirEvent resize_event; + + mir_surface_get_graphics_region (impl->surface, ®ion); + + /* Send the initial configure with the size the server gave... */ + resize_event.resize.type = mir_event_type_resize; + resize_event.resize.surface_id = 0; + resize_event.resize.width = region.width; + resize_event.resize.height = region.height; + + _gdk_mir_event_source_queue (window_ref, &resize_event); + + mir_surface_set_event_handler (impl->surface, &event_delegate); // FIXME: Ignore some events until shown + set_surface_state (impl, impl->surface_state); +} + +static void +ensure_no_surface (GdkWindow *window) +{ + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + + if (impl->cairo_surface) + { + cairo_surface_finish (impl->cairo_surface); + cairo_surface_destroy (impl->cairo_surface); + impl->cairo_surface = NULL; + } + + if (impl->surface) + { + mir_surface_release_sync (impl->surface); + impl->surface = NULL; + } +} + +static void +redraw_transient (GdkWindow *window) +{ + GdkRectangle r; + r.x = window->x; + r.y = window->y; + r.width = window->width; + r.height = window->height; + gdk_window_invalidate_rect (GDK_MIR_WINDOW_IMPL (window->impl)->transient_for, &r, FALSE); +} + +static void +send_buffer (GdkWindow *window) +{ + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + + /* Transient windows draw onto parent instead */ + if (impl->transient_for) + { + redraw_transient (window); + return; + } + + /* Composite transient windows over this one */ + if (impl->transient_children) + { + cairo_surface_t *surface; + cairo_t *c; + GList *link; + + surface = gdk_mir_window_impl_ref_cairo_surface (window); + c = cairo_create (surface); + + for (link = impl->transient_children; link; link = link->next) + { + GdkWindow *child_window = link->data; + GdkMirWindowImpl *child_impl = GDK_MIR_WINDOW_IMPL (child_window->impl); + + /* Skip children not yet drawn to */ + if (!child_impl->cairo_surface) + continue; + + cairo_set_source_surface (c, child_impl->cairo_surface, child_window->x, child_window->y); + cairo_rectangle (c, child_window->x, child_window->y, child_window->width, child_window->height); + cairo_fill (c); + } + + cairo_destroy (c); + cairo_surface_destroy (surface); + } + + /* Send the completed buffer to Mir */ + mir_surface_swap_buffers_sync (impl->surface); + + /* The Cairo context is no longer valid */ + if (impl->cairo_surface) + { + cairo_surface_destroy (impl->cairo_surface); + impl->cairo_surface = NULL; + } +} + +static cairo_surface_t * +gdk_mir_window_impl_ref_cairo_surface (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_ref_cairo_surface window=%p\n", window); + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + MirGraphicsRegion region; + cairo_format_t pixel_format = CAIRO_FORMAT_INVALID; + cairo_surface_t *cairo_surface; + cairo_t *c; + + if (impl->cairo_surface) + { + cairo_surface_reference (impl->cairo_surface); + return impl->cairo_surface; + } + + /* Transient windows get rendered into a buffer and copied onto their parent */ + if (impl->transient_for) + { + cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, window->width, window->height); + } + else + { + ensure_surface (window); + + mir_surface_get_graphics_region (impl->surface, ®ion); + + // FIXME: Should calculate this once + switch (region.pixel_format) + { + case mir_pixel_format_argb_8888: + pixel_format = CAIRO_FORMAT_ARGB32; + break; + default: + case mir_pixel_format_abgr_8888: + case mir_pixel_format_xbgr_8888: + case mir_pixel_format_xrgb_8888: + case mir_pixel_format_bgr_888: + // uh-oh... + g_printerr ("Unsupported pixel format %d\n", region.pixel_format); + break; + } + + cairo_surface = cairo_image_surface_create_for_data ((unsigned char *) region.vaddr, + pixel_format, + region.width, + region.height, + region.stride); + } + + impl->cairo_surface = cairo_surface_reference (cairo_surface); + + /* Draw background */ + c = cairo_create (impl->cairo_surface); + if (impl->background) + cairo_set_source (c, impl->background); + else + cairo_set_source_rgb (c, 1.0, 0.0, 0.0); + cairo_paint (c); + cairo_destroy (c); + + return cairo_surface; +} + +static cairo_surface_t * +gdk_mir_window_impl_create_similar_image_surface (GdkWindow *window, + cairo_format_t format, + int width, + int height) +{ + //g_printerr ("gdk_mir_window_impl_create_similar_image_surface window=%p\n", window); + return cairo_image_surface_create (format, width, height); +} + +static void +gdk_mir_window_impl_finalize (GObject *object) +{ + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (object); + GList *link; + + for (link = impl->transient_children; link; link = link->next) + { + GdkWindow *window = link->data; + gdk_window_destroy (window); + } + + if (impl->background) + cairo_pattern_destroy (impl->background); + if (impl->surface) + mir_surface_release_sync (impl->surface); + if (impl->cairo_surface) + cairo_surface_destroy (impl->cairo_surface); + g_list_free (impl->transient_children); + + G_OBJECT_CLASS (gdk_mir_window_impl_parent_class)->finalize (object); +} + +static void +gdk_mir_window_impl_show (GdkWindow *window, + gboolean already_mapped) +{ + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + cairo_surface_t *s; + + //g_printerr ("gdk_mir_window_impl_show window=%p\n", window); + + impl->visible = TRUE; + + /* Make sure there's a surface to see */ + ensure_surface (window); + + /* Make sure something is rendered and then show first frame */ + s = gdk_mir_window_impl_ref_cairo_surface (window); + send_buffer (window); + cairo_surface_destroy (s); +} + +static void +gdk_mir_window_impl_hide (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_hide window=%p\n", window); + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + + impl->visible = FALSE; + ensure_no_surface (window); + + if (impl->transient_for) + redraw_transient (window); +} + +static void +gdk_mir_window_impl_withdraw (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_withdraw window=%p\n", window); + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + + impl->visible = FALSE; + ensure_no_surface (window); + + if (impl->transient_for) + redraw_transient (window); +} + +static void +gdk_mir_window_impl_raise (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_raise window=%p\n", window); + /* We don't support client window stacking */ +} + +static void +gdk_mir_window_impl_lower (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_lower window=%p\n", window); + /* We don't support client window stacking */ +} + +static void +gdk_mir_window_impl_restack_under (GdkWindow *window, + GList *native_siblings) +{ + //g_printerr ("gdk_mir_window_impl_restack_under window=%p\n", window); + /* We don't support client window stacking */ +} + +static void +gdk_mir_window_impl_restack_toplevel (GdkWindow *window, + GdkWindow *sibling, + gboolean above) +{ + //g_printerr ("gdk_mir_window_impl_restack_toplevel window=%p sibling=%p\n", window, sibling); + /* We don't support client window stacking */ +} + +static void +gdk_mir_window_impl_move_resize (GdkWindow *window, + gboolean with_move, + gint x, + gint y, + gint width, + gint height) +{ + g_printerr ("gdk_mir_window_impl_move_resize"); + g_printerr (" window=%p", window); + if (with_move) + g_printerr (" location=%d,%d", x, y); + if (width > 0) + g_printerr (" size=%dx%dpx", width, height); + g_printerr ("\n"); + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + + /* Redraw parent where we moved from */ + if (impl->transient_for) + redraw_transient (window); + + /* Transient windows can move wherever they want */ + if (with_move) + { + if (impl->transient_for) + { + window->x = x; + window->y = y; + } + else + { + impl->transient_x = x; + impl->transient_y = y; + } + } + + /* If resize requested then rebuild surface */ + if (width >= 0) + { + /* We accept any resize */ + window->width = width; + window->height = height; + + if (impl->surface) + { + ensure_no_surface (window); + ensure_surface (window); + } + } + + /* Redraw parent where we moved to */ + if (impl->transient_for) + redraw_transient (window); +} + +static void +gdk_mir_window_impl_set_background (GdkWindow *window, + cairo_pattern_t *pattern) +{ + //g_printerr ("gdk_mir_window_impl_set_background window=%p\n", window); + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + + if (impl->background) + cairo_pattern_destroy (impl->background); + impl->background = cairo_pattern_reference (pattern); +} + +static GdkEventMask +gdk_mir_window_impl_get_events (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_get_events window=%p\n", window); + return window->event_mask; +} + +static void +gdk_mir_window_impl_set_events (GdkWindow *window, + GdkEventMask event_mask) +{ + //g_printerr ("gdk_mir_window_impl_set_events window=%p\n", window); + /* We send all events and let GDK decide */ +} + +static gboolean +gdk_mir_window_impl_reparent (GdkWindow *window, + GdkWindow *new_parent, + gint x, + gint y) +{ + g_printerr ("gdk_mir_window_impl_reparent window=%p new-parent=%p\n", window, new_parent); + return FALSE; +} + +static void +gdk_mir_window_impl_set_device_cursor (GdkWindow *window, + GdkDevice *device, + GdkCursor *cursor) +{ + //g_printerr ("gdk_mir_window_impl_set_device_cursor window=%p\n", window); + /* We don't support cursors yet... */ +} + +static void +gdk_mir_window_impl_get_geometry (GdkWindow *window, + gint *x, + gint *y, + gint *width, + gint *height) +{ + //g_printerr ("gdk_mir_window_impl_get_geometry window=%p\n", window); + + if (x) + *x = 0; // FIXME + if (y) + *y = 0; // FIXME + if (width) + *width = window->width; + if (height) + *height = window->height; +} + +static void +gdk_mir_window_impl_get_root_coords (GdkWindow *window, + gint x, + gint y, + gint *root_x, + gint *root_y) +{ + //g_printerr ("gdk_mir_window_impl_get_root_coords window=%p\n", window); + + if (root_x) + *root_x = x; // FIXME + if (root_y) + *root_y = y; // FIXME +} + +static gboolean +gdk_mir_window_impl_get_device_state (GdkWindow *window, + GdkDevice *device, + gdouble *x, + gdouble *y, + GdkModifierType *mask) +{ + //g_printerr ("gdk_mir_window_impl_get_device_state window=%p\n", window); + GdkWindow *child; + + _gdk_device_query_state (device, window, NULL, &child, NULL, NULL, x, y, mask); + + return child != NULL; +} + +static gboolean +gdk_mir_window_impl_begin_paint_region (GdkWindow *window, + const cairo_region_t *region) +{ + //g_printerr ("gdk_mir_window_impl_begin_paint_region window=%p\n", window); + /* Indicate we are ready to be drawn onto directly? */ + return FALSE; +} + +static void +gdk_mir_window_impl_end_paint (GdkWindow *window) +{ + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + + //g_printerr ("gdk_mir_window_impl_end_paint window=%p\n", window); + if (impl->visible) + send_buffer (window); +} + +static cairo_region_t * +gdk_mir_window_impl_get_shape (GdkWindow *window) +{ + g_printerr ("gdk_mir_window_impl_get_shape window=%p\n", window); + return NULL; +} + +static cairo_region_t * +gdk_mir_window_impl_get_input_shape (GdkWindow *window) +{ + g_printerr ("gdk_mir_window_impl_get_input_shape window=%p\n", window); + return NULL; +} + +static void +gdk_mir_window_impl_shape_combine_region (GdkWindow *window, + const cairo_region_t *shape_region, + gint offset_x, + gint offset_y) +{ + g_printerr ("gdk_mir_window_impl_shape_combine_region window=%p\n", window); +} + +static void +gdk_mir_window_impl_input_shape_combine_region (GdkWindow *window, + const cairo_region_t *shape_region, + gint offset_x, + gint offset_y) +{ + g_printerr ("gdk_mir_window_impl_input_shape_combine_region window=%p\n", window); +} + +static void +gdk_mir_window_impl_destroy (GdkWindow *window, + gboolean recursing, + gboolean foreign_destroy) +{ + //g_printerr ("gdk_mir_window_impl_destroy window=%p\n", window); + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + + impl->visible = FALSE; + ensure_no_surface (window); + + if (impl->transient_for) + { + /* Redraw parent */ + redraw_transient (window); + + /* Remove from transient list */ + GdkMirWindowImpl *parent_impl = GDK_MIR_WINDOW_IMPL (impl->transient_for->impl); + parent_impl->transient_children = g_list_remove (parent_impl->transient_children, window); + } +} + +static void +gdk_mir_window_impl_destroy_foreign (GdkWindow *window) +{ + g_printerr ("gdk_mir_window_impl_destroy_foreign window=%p\n", window); +} + +static void +gdk_mir_window_impl_focus (GdkWindow *window, + guint32 timestamp) +{ + g_printerr ("gdk_mir_window_impl_focus window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_type_hint (GdkWindow *window, + GdkWindowTypeHint hint) +{ + //g_printerr ("gdk_mir_window_impl_set_type_hint window=%p\n", window); + // FIXME: ? +} + +static GdkWindowTypeHint +gdk_mir_window_impl_get_type_hint (GdkWindow *window) +{ + g_printerr ("gdk_mir_window_impl_get_type_hint window=%p\n", window); + return GDK_WINDOW_TYPE_HINT_NORMAL; +} + +void +gdk_mir_window_impl_set_modal_hint (GdkWindow *window, + gboolean modal) +{ + //g_printerr ("gdk_mir_window_impl_set_modal_hint window=%p\n", window); + /* Mir doesn't support modal windows */ +} + +static void +gdk_mir_window_impl_set_skip_taskbar_hint (GdkWindow *window, + gboolean skips_taskbar) +{ + g_printerr ("gdk_mir_window_impl_set_skip_taskbar_hint window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_skip_pager_hint (GdkWindow *window, + gboolean skips_pager) +{ + g_printerr ("gdk_mir_window_impl_set_skip_pager_hint window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_urgency_hint (GdkWindow *window, + gboolean urgent) +{ + g_printerr ("gdk_mir_window_impl_set_urgency_hint window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_geometry_hints (GdkWindow *window, + const GdkGeometry *geometry, + GdkWindowHints geom_mask) +{ + //g_printerr ("gdk_mir_window_impl_set_geometry_hints window=%p\n", window); + //FIXME: ? +} + +static void +gdk_mir_window_impl_set_title (GdkWindow *window, + const gchar *title) +{ + g_printerr ("gdk_mir_window_impl_set_title window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_role (GdkWindow *window, + const gchar *role) +{ + g_printerr ("gdk_mir_window_impl_set_role window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_startup_id (GdkWindow *window, + const gchar *startup_id) +{ + g_printerr ("gdk_mir_window_impl_set_startup_id window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_transient_for (GdkWindow *window, + GdkWindow *parent) +{ + g_printerr ("gdk_mir_window_impl_set_transient_for window=%p\n", window); + GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl); + + if (impl->transient_for == parent) + return; + + g_return_if_fail (impl->transient_for == NULL); + + /* Link this window to the parent */ + impl->transient_for = parent; + if (parent) + { + GdkMirWindowImpl *parent_impl = GDK_MIR_WINDOW_IMPL (parent->impl); + parent_impl->transient_children = g_list_append (parent_impl->transient_children, window); + + /* Move to where the client requested */ + window->x = impl->transient_x; + window->y = impl->transient_y; + + /* Redraw onto parent */ + redraw_transient (window); + } + + /* Remove surface if we had made one before this was set */ + ensure_no_surface (window); +} + +static void +gdk_mir_window_impl_get_frame_extents (GdkWindow *window, + GdkRectangle *rect) +{ + g_printerr ("gdk_mir_window_impl_get_frame_extents window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_override_redirect (GdkWindow *window, + gboolean override_redirect) +{ + g_printerr ("gdk_mir_window_impl_set_override_redirect window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_accept_focus (GdkWindow *window, + gboolean accept_focus) +{ + //g_printerr ("gdk_mir_window_impl_set_accept_focus window=%p\n", window); + /* Mir clients cannot control focus */ +} + +static void +gdk_mir_window_impl_set_focus_on_map (GdkWindow *window, + gboolean focus_on_map) +{ + //g_printerr ("gdk_mir_window_impl_set_focus_on_map window=%p\n", window); + /* Mir clients cannot control focus */ +} + +static void +gdk_mir_window_impl_set_icon_list (GdkWindow *window, + GList *pixbufs) +{ + //g_printerr ("gdk_mir_window_impl_set_icon_list window=%p\n", window); + // ?? +} + +static void +gdk_mir_window_impl_set_icon_name (GdkWindow *window, + const gchar *name) +{ + g_printerr ("gdk_mir_window_impl_set_icon_name window=%p\n", window); +} + +static void +gdk_mir_window_impl_iconify (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_iconify window=%p\n", window); + /* We don't support iconification */ +} + +static void +gdk_mir_window_impl_deiconify (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_deiconify window=%p\n", window); + /* We don't support iconification */ +} + +static void +gdk_mir_window_impl_stick (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_stick window=%p\n", window); + /* We do not support stick/unstick in Mir */ +} + +static void +gdk_mir_window_impl_unstick (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_unstick window=%p\n", window); + /* We do not support stick/unstick in Mir */ +} + +static void +gdk_mir_window_impl_maximize (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_maximize window=%p\n", window); + set_surface_state (GDK_MIR_WINDOW_IMPL (window->impl), mir_surface_state_maximized); +} + +static void +gdk_mir_window_impl_unmaximize (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_unmaximize window=%p\n", window); + set_surface_state (GDK_MIR_WINDOW_IMPL (window->impl), mir_surface_state_restored); +} + +static void +gdk_mir_window_impl_fullscreen (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_fullscreen window=%p\n", window); + set_surface_state (GDK_MIR_WINDOW_IMPL (window->impl), mir_surface_state_fullscreen); +} + +static void +gdk_mir_window_impl_apply_fullscreen_mode (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_apply_fullscreen_mode window=%p\n", window); +} + +static void +gdk_mir_window_impl_unfullscreen (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_unfullscreen window=%p\n", window); + set_surface_state (GDK_MIR_WINDOW_IMPL (window->impl), mir_surface_state_restored); +} + +static void +gdk_mir_window_impl_set_keep_above (GdkWindow *window, + gboolean setting) +{ + //g_printerr ("gdk_mir_window_impl_set_keep_above window=%p\n", window); + /* We do not support keep above/below in Mir */ +} + +static void +gdk_mir_window_impl_set_keep_below (GdkWindow *window, + gboolean setting) +{ + //g_printerr ("gdk_mir_window_impl_set_keep_below window=%p\n", window); + /* We do not support keep above/below in Mir */ +} + +static GdkWindow * +gdk_mir_window_impl_get_group (GdkWindow *window) +{ + g_printerr ("gdk_mir_window_impl_get_group window=%p\n", window); + return NULL; +} + +static void +gdk_mir_window_impl_set_group (GdkWindow *window, + GdkWindow *leader) +{ + g_printerr ("gdk_mir_window_impl_set_group window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_decorations (GdkWindow *window, + GdkWMDecoration decorations) +{ + g_printerr ("gdk_mir_window_impl_set_decorations window=%p decorations=%d\n", window, decorations); +} + +static gboolean +gdk_mir_window_impl_get_decorations (GdkWindow *window, + GdkWMDecoration *decorations) +{ + g_printerr ("gdk_mir_window_impl_get_decorations window=%p\n", window); + return FALSE; +} + +static void +gdk_mir_window_impl_set_functions (GdkWindow *window, + GdkWMFunction functions) +{ + g_printerr ("gdk_mir_window_impl_set_functions window=%p\n", window); +} + +static void +gdk_mir_window_impl_begin_resize_drag (GdkWindow *window, + GdkWindowEdge edge, + GdkDevice *device, + gint button, + gint root_x, + gint root_y, + guint32 timestamp) +{ + g_printerr ("gdk_mir_window_impl_begin_resize_drag window=%p\n", window); +} + +static void +gdk_mir_window_impl_begin_move_drag (GdkWindow *window, + GdkDevice *device, + gint button, + gint root_x, + gint root_y, + guint32 timestamp) +{ + g_printerr ("gdk_mir_window_impl_begin_move_drag window=%p\n", window); +} + +static void +gdk_mir_window_impl_enable_synchronized_configure (GdkWindow *window) +{ + g_printerr ("gdk_mir_window_impl_enable_synchronized_configure window=%p\n", window); +} + +static void +gdk_mir_window_impl_configure_finished (GdkWindow *window) +{ + g_printerr ("gdk_mir_window_impl_configure_finished window=%p\n", window); +} + +static void +gdk_mir_window_impl_set_opacity (GdkWindow *window, + gdouble opacity) +{ + //g_printerr ("gdk_mir_window_impl_set_opacity window=%p\n", window); + // FIXME +} + +static void +gdk_mir_window_impl_set_composited (GdkWindow *window, + gboolean composited) +{ + g_printerr ("gdk_mir_window_impl_set_composited window=%p\n", window); +} + +static void +gdk_mir_window_impl_destroy_notify (GdkWindow *window) +{ + g_printerr ("gdk_mir_window_impl_destroy_notify window=%p\n", window); +} + +static GdkDragProtocol +gdk_mir_window_impl_get_drag_protocol (GdkWindow *window, + GdkWindow **target) +{ + g_printerr ("gdk_mir_window_impl_get_drag_protocol window=%p\n", window); + return 0; +} + +static void +gdk_mir_window_impl_register_dnd (GdkWindow *window) +{ + g_printerr ("gdk_mir_window_impl_register_dnd window=%p\n", window); +} + +static GdkDragContext * +gdk_mir_window_impl_drag_begin (GdkWindow *window, + GdkDevice *device, + GList *targets) +{ + g_printerr ("gdk_mir_window_impl_drag_begin window=%p\n", window); + return NULL; +} + +static void +gdk_mir_window_impl_process_updates_recurse (GdkWindow *window, + cairo_region_t *region) +{ + //g_printerr ("gdk_mir_window_impl_process_updates_recurse window=%p\n", window); + cairo_rectangle_int_t rectangle; + + /* We redraw the whole region, but we should track the buffers and only redraw what has changed since we sent this buffer */ + rectangle.x = 0; + rectangle.y = 0; + rectangle.width = window->width; + rectangle.height = window->height; + cairo_region_union_rectangle (region, &rectangle); + + _gdk_window_process_updates_recurse (window, region); +} + +static void +gdk_mir_window_impl_sync_rendering (GdkWindow *window) +{ + g_printerr ("gdk_mir_window_impl_sync_rendering window=%p\n", window); + // FIXME: Only used for benchmarking +} + +static gboolean +gdk_mir_window_impl_simulate_key (GdkWindow *window, + gint x, + gint y, + guint keyval, + GdkModifierType modifiers, + GdkEventType key_pressrelease) +{ + g_printerr ("gdk_mir_window_impl_simulate_key window=%p\n", window); + return FALSE; +} + +static gboolean +gdk_mir_window_impl_simulate_button (GdkWindow *window, + gint x, + gint y, + guint button, + GdkModifierType modifiers, + GdkEventType button_pressrelease) +{ + g_printerr ("gdk_mir_window_impl_simulate_button window=%p\n", window); + return FALSE; +} + +static gboolean +gdk_mir_window_impl_get_property (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gulong offset, + gulong length, + gint pdelete, + GdkAtom *actual_property_type, + gint *actual_format_type, + gint *actual_length, + guchar **data) +{ + g_printerr ("gdk_mir_window_impl_get_property window=%p\n", window); + return FALSE; +} + +static void +gdk_mir_window_impl_change_property (GdkWindow *window, + GdkAtom property, + GdkAtom type, + gint format, + GdkPropMode mode, + const guchar *data, + gint nelements) +{ + g_printerr ("gdk_mir_window_impl_change_property window=%p\n", window); +} + +static void +gdk_mir_window_impl_delete_property (GdkWindow *window, + GdkAtom property) +{ + //g_printerr ("gdk_mir_window_impl_delete_property window=%p\n", window); +} + +static gint +gdk_mir_window_impl_get_scale_factor (GdkWindow *window) +{ + //g_printerr ("gdk_mir_window_impl_get_scale_factor window=%p\n", window); + /* Don't support monitor scaling */ + return 1; +} + +static void +gdk_mir_window_impl_set_opaque_region (GdkWindow *window, + cairo_region_t *region) +{ + //g_printerr ("gdk_mir_window_impl_set_opaque_region window=%p\n", window); + /* FIXME: An optimisation to tell the compositor which regions of the window are fully transparent */ +} + +static void +gdk_mir_window_impl_set_shadow_width (GdkWindow *window, + gint left, + gint right, + gint top, + gint bottom) +{ + g_printerr ("gdk_mir_window_impl_set_shadow_width window=%p\n", window); +} + +static void +gdk_mir_window_impl_class_init (GdkMirWindowImplClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass); + + object_class->finalize = gdk_mir_window_impl_finalize; + + impl_class->ref_cairo_surface = gdk_mir_window_impl_ref_cairo_surface; + impl_class->create_similar_image_surface = gdk_mir_window_impl_create_similar_image_surface; + impl_class->show = gdk_mir_window_impl_show; + impl_class->hide = gdk_mir_window_impl_hide; + impl_class->withdraw = gdk_mir_window_impl_withdraw; + impl_class->raise = gdk_mir_window_impl_raise; + impl_class->lower = gdk_mir_window_impl_lower; + impl_class->restack_under = gdk_mir_window_impl_restack_under; + impl_class->restack_toplevel = gdk_mir_window_impl_restack_toplevel; + impl_class->move_resize = gdk_mir_window_impl_move_resize; + impl_class->set_background = gdk_mir_window_impl_set_background; + impl_class->get_events = gdk_mir_window_impl_get_events; + impl_class->set_events = gdk_mir_window_impl_set_events; + impl_class->reparent = gdk_mir_window_impl_reparent; + impl_class->set_device_cursor = gdk_mir_window_impl_set_device_cursor; + impl_class->get_geometry = gdk_mir_window_impl_get_geometry; + impl_class->get_root_coords = gdk_mir_window_impl_get_root_coords; + impl_class->get_device_state = gdk_mir_window_impl_get_device_state; + impl_class->begin_paint_region = gdk_mir_window_impl_begin_paint_region; + impl_class->end_paint = gdk_mir_window_impl_end_paint; + impl_class->get_shape = gdk_mir_window_impl_get_shape; + impl_class->get_input_shape = gdk_mir_window_impl_get_input_shape; + impl_class->shape_combine_region = gdk_mir_window_impl_shape_combine_region; + impl_class->input_shape_combine_region = gdk_mir_window_impl_input_shape_combine_region; + impl_class->destroy = gdk_mir_window_impl_destroy; + impl_class->destroy_foreign = gdk_mir_window_impl_destroy_foreign; + impl_class->focus = gdk_mir_window_impl_focus; + impl_class->set_type_hint = gdk_mir_window_impl_set_type_hint; + impl_class->get_type_hint = gdk_mir_window_impl_get_type_hint; + impl_class->set_modal_hint = gdk_mir_window_impl_set_modal_hint; + impl_class->set_skip_taskbar_hint = gdk_mir_window_impl_set_skip_taskbar_hint; + impl_class->set_skip_pager_hint = gdk_mir_window_impl_set_skip_pager_hint; + impl_class->set_urgency_hint = gdk_mir_window_impl_set_urgency_hint; + impl_class->set_geometry_hints = gdk_mir_window_impl_set_geometry_hints; + impl_class->set_title = gdk_mir_window_impl_set_title; + impl_class->set_role = gdk_mir_window_impl_set_role; + impl_class->set_startup_id = gdk_mir_window_impl_set_startup_id; + impl_class->set_transient_for = gdk_mir_window_impl_set_transient_for; + impl_class->get_frame_extents = gdk_mir_window_impl_get_frame_extents; + impl_class->set_override_redirect = gdk_mir_window_impl_set_override_redirect; + impl_class->set_accept_focus = gdk_mir_window_impl_set_accept_focus; + impl_class->set_focus_on_map = gdk_mir_window_impl_set_focus_on_map; + impl_class->set_icon_list = gdk_mir_window_impl_set_icon_list; + impl_class->set_icon_name = gdk_mir_window_impl_set_icon_name; + impl_class->iconify = gdk_mir_window_impl_iconify; + impl_class->deiconify = gdk_mir_window_impl_deiconify; + impl_class->stick = gdk_mir_window_impl_stick; + impl_class->unstick = gdk_mir_window_impl_unstick; + impl_class->maximize = gdk_mir_window_impl_maximize; + impl_class->unmaximize = gdk_mir_window_impl_unmaximize; + impl_class->fullscreen = gdk_mir_window_impl_fullscreen; + impl_class->apply_fullscreen_mode = gdk_mir_window_impl_apply_fullscreen_mode; + impl_class->unfullscreen = gdk_mir_window_impl_unfullscreen; + impl_class->set_keep_above = gdk_mir_window_impl_set_keep_above; + impl_class->set_keep_below = gdk_mir_window_impl_set_keep_below; + impl_class->get_group = gdk_mir_window_impl_get_group; + impl_class->set_group = gdk_mir_window_impl_set_group; + impl_class->set_decorations = gdk_mir_window_impl_set_decorations; + impl_class->get_decorations = gdk_mir_window_impl_get_decorations; + impl_class->set_functions = gdk_mir_window_impl_set_functions; + impl_class->begin_resize_drag = gdk_mir_window_impl_begin_resize_drag; + impl_class->begin_move_drag = gdk_mir_window_impl_begin_move_drag; + impl_class->enable_synchronized_configure = gdk_mir_window_impl_enable_synchronized_configure; + impl_class->configure_finished = gdk_mir_window_impl_configure_finished; + impl_class->set_opacity = gdk_mir_window_impl_set_opacity; + impl_class->set_composited = gdk_mir_window_impl_set_composited; + impl_class->destroy_notify = gdk_mir_window_impl_destroy_notify; + impl_class->get_drag_protocol = gdk_mir_window_impl_get_drag_protocol; + impl_class->register_dnd = gdk_mir_window_impl_register_dnd; + impl_class->drag_begin = gdk_mir_window_impl_drag_begin; + impl_class->process_updates_recurse = gdk_mir_window_impl_process_updates_recurse; + impl_class->sync_rendering = gdk_mir_window_impl_sync_rendering; + impl_class->simulate_key = gdk_mir_window_impl_simulate_key; + impl_class->simulate_button = gdk_mir_window_impl_simulate_button; + impl_class->get_property = gdk_mir_window_impl_get_property; + impl_class->change_property = gdk_mir_window_impl_change_property; + impl_class->delete_property = gdk_mir_window_impl_delete_property; + impl_class->get_scale_factor = gdk_mir_window_impl_get_scale_factor; + impl_class->set_opaque_region = gdk_mir_window_impl_set_opaque_region; + impl_class->set_shadow_width = gdk_mir_window_impl_set_shadow_width; +} diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c index 8c3f2dfb28..ea762102b6 100644 --- a/gtk/gtktooltip.c +++ b/gtk/gtktooltip.c @@ -40,6 +40,9 @@ #ifdef GDK_WINDOWING_WAYLAND #include "wayland/gdkwayland.h" #endif +#ifdef GDK_WINDOWING_MIR +#include "mir/gdkmir.h" +#endif /** @@ -1169,6 +1172,19 @@ found: GTK_WINDOW (toplevel)); } #endif +#ifdef GDK_WINDOWING_MIR + /* Set the transient parent on the tooltip when running with the Mir + * backend to allow correct positioning of the tooltip windows */ + if (GDK_IS_MIR_DISPLAY (display)) + { + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (tooltip->tooltip_widget); + if (GTK_IS_WINDOW (toplevel)) + gtk_window_set_transient_for (GTK_WINDOW (tooltip->current_window), + GTK_WINDOW (toplevel)); + } +#endif x -= border.left; y -= border.top; -- 2.30.2